plugins/mapchooser.sp
author David Anderson <dvander@alliedmods.net>
Fri Jul 11 06:51:21 2008 +0000 (2008-07-11)
branchrefac-jit
changeset 2192 7602d7fb60d9
parent 2168 c24a6fa957db
permissions -rw-r--r--
fixed a compat regression, forgot msvc does funky things with overloaded virtual calls
dvander@2168
     1
/**
dvander@2168
     2
 * vim: set ts=4 :
dvander@2168
     3
 * =============================================================================
dvander@2168
     4
 * SourceMod Mapchooser Plugin
dvander@2168
     5
 * Creates a map vote at appropriate times, setting sm_nextmap to the winning
dvander@2168
     6
 * vote
dvander@2168
     7
 *
dvander@2168
     8
 * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
dvander@2168
     9
 * =============================================================================
dvander@2168
    10
 *
dvander@2168
    11
 * This program is free software; you can redistribute it and/or modify it under
dvander@2168
    12
 * the terms of the GNU General Public License, version 3.0, as published by the
dvander@2168
    13
 * Free Software Foundation.
dvander@2168
    14
 * 
dvander@2168
    15
 * This program is distributed in the hope that it will be useful, but WITHOUT
dvander@2168
    16
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@2168
    17
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
dvander@2168
    18
 * details.
dvander@2168
    19
 *
dvander@2168
    20
 * You should have received a copy of the GNU General Public License along with
dvander@2168
    21
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@2168
    22
 *
dvander@2168
    23
 * As a special exception, AlliedModders LLC gives you permission to link the
dvander@2168
    24
 * code of this program (as well as its derivative works) to "Half-Life 2," the
dvander@2168
    25
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
dvander@2168
    26
 * by the Valve Corporation.  You must obey the GNU General Public License in
dvander@2168
    27
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
dvander@2168
    28
 * this exception to all derivative works.  AlliedModders LLC defines further
dvander@2168
    29
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
dvander@2168
    30
 * or <http://www.sourcemod.net/license.php>.
dvander@2168
    31
 *
dvander@2168
    32
 * Version: $Id$
dvander@2168
    33
 */
dvander@2168
    34
dvander@2168
    35
#pragma semicolon 1
dvander@2168
    36
#include <sourcemod>
dvander@2168
    37
#include <mapchooser>
dvander@2168
    38
#include <nextmap>
dvander@2168
    39
#undef REQUIRE_EXTENSIONS
dvander@2168
    40
#include <tf2>
dvander@2168
    41
#define REQUIRE_EXTENSIONS
dvander@2168
    42
dvander@2168
    43
public Plugin:myinfo =
dvander@2168
    44
{
dvander@2168
    45
	name = "MapChooser",
dvander@2168
    46
	author = "AlliedModders LLC",
dvander@2168
    47
	description = "Automated Map Voting",
dvander@2168
    48
	version = SOURCEMOD_VERSION,
dvander@2168
    49
	url = "http://www.sourcemod.net/"
dvander@2168
    50
};
dvander@2168
    51
dvander@2168
    52
/* Valve ConVars */
dvander@2168
    53
new Handle:g_Cvar_Winlimit = INVALID_HANDLE;
dvander@2168
    54
new Handle:g_Cvar_Maxrounds = INVALID_HANDLE;
dvander@2168
    55
new Handle:g_Cvar_Fraglimit = INVALID_HANDLE;
dvander@2168
    56
new Handle:g_Cvar_Bonusroundtime = INVALID_HANDLE;
dvander@2168
    57
dvander@2168
    58
/* Plugin ConVars */
dvander@2168
    59
new Handle:g_Cvar_StartTime = INVALID_HANDLE;
dvander@2168
    60
new Handle:g_Cvar_StartRounds = INVALID_HANDLE;
dvander@2168
    61
new Handle:g_Cvar_StartFrags = INVALID_HANDLE;
dvander@2168
    62
new Handle:g_Cvar_ExtendTimeStep = INVALID_HANDLE;
dvander@2168
    63
new Handle:g_Cvar_ExtendRoundStep = INVALID_HANDLE;
dvander@2168
    64
new Handle:g_Cvar_ExtendFragStep = INVALID_HANDLE;
dvander@2168
    65
new Handle:g_Cvar_ExcludeMaps = INVALID_HANDLE;
dvander@2168
    66
new Handle:g_Cvar_IncludeMaps = INVALID_HANDLE;
dvander@2168
    67
new Handle:g_Cvar_NoVoteMode = INVALID_HANDLE;
dvander@2168
    68
new Handle:g_Cvar_Extend = INVALID_HANDLE;
dvander@2168
    69
new Handle:g_Cvar_DontChange = INVALID_HANDLE;
dvander@2168
    70
new Handle:g_Cvar_EndOfMapVote = INVALID_HANDLE;
dvander@2168
    71
new Handle:g_Cvar_VoteDuration = INVALID_HANDLE;
dvander@2168
    72
new Handle:g_VoteTimer = INVALID_HANDLE;
dvander@2168
    73
new Handle:g_RetryTimer = INVALID_HANDLE;
dvander@2168
    74
dvander@2168
    75
/* Data Handles */
dvander@2168
    76
new Handle:g_MapList = INVALID_HANDLE;
dvander@2168
    77
new Handle:g_NominateList = INVALID_HANDLE;
dvander@2168
    78
new Handle:g_NominateOwners = INVALID_HANDLE;
dvander@2168
    79
new Handle:g_OldMapList = INVALID_HANDLE;
dvander@2168
    80
new Handle:g_NextMapList = INVALID_HANDLE;
dvander@2168
    81
new Handle:g_VoteMenu = INVALID_HANDLE;
dvander@2168
    82
dvander@2168
    83
new g_Extends;
dvander@2168
    84
new g_TotalRounds;
dvander@2168
    85
new bool:g_HasVoteStarted;
dvander@2168
    86
new bool:g_WaitingForVote;
dvander@2168
    87
new bool:g_MapVoteCompleted;
dvander@2168
    88
new bool:g_ChangeMapAtRoundEnd;
dvander@2168
    89
new g_mapFileSerial = -1;
dvander@2168
    90
dvander@2168
    91
new g_NominateCount = 0;
dvander@2168
    92
new MapChange:g_ChangeTime;
dvander@2168
    93
dvander@2168
    94
new Handle:g_NominationsResetForward = INVALID_HANDLE;
dvander@2168
    95
dvander@2168
    96
/* Upper bound of how many team there could be */
dvander@2168
    97
#define MAXTEAMS 10
dvander@2168
    98
new g_winCount[MAXTEAMS];
dvander@2168
    99
dvander@2168
   100
#define VOTE_EXTEND "##extend##"
dvander@2168
   101
#define VOTE_DONTCHANGE "##dontchange##"
dvander@2168
   102
dvander@2168
   103
public OnPluginStart()
dvander@2168
   104
{
dvander@2168
   105
	LoadTranslations("mapchooser.phrases");
dvander@2168
   106
	
dvander@2168
   107
	new arraySize = ByteCountToCells(33);
dvander@2168
   108
	g_MapList = CreateArray(arraySize);
dvander@2168
   109
	g_NominateList = CreateArray(arraySize);
dvander@2168
   110
	g_NominateOwners = CreateArray(1);
dvander@2168
   111
	g_OldMapList = CreateArray(arraySize);
dvander@2168
   112
	g_NextMapList = CreateArray(arraySize);
dvander@2168
   113
	
dvander@2168
   114
	g_Cvar_EndOfMapVote = CreateConVar("sm_mapvote_endvote", "1", "Specifies if MapChooser should run an end of map vote", _, true, 0.0, true, 1.0);
dvander@2168
   115
	HookConVarChange(g_Cvar_EndOfMapVote, EndVoteChanged);
dvander@2168
   116
dvander@2168
   117
	g_Cvar_StartTime = CreateConVar("sm_mapvote_start", "3.0", "Specifies when to start the vote based on time remaining.", _, true, 1.0);
dvander@2168
   118
	g_Cvar_StartRounds = CreateConVar("sm_mapvote_startround", "2.0", "Specifies when to start the vote based on rounds remaining. Use 0 on TF2 to start vote during bonus round time", _, true, 0.0);
dvander@2168
   119
	g_Cvar_StartFrags = CreateConVar("sm_mapvote_startfrags", "5.0", "Specifies when to start the vote base on frags remaining.", _, true, 1.0);
dvander@2168
   120
	g_Cvar_ExtendTimeStep = CreateConVar("sm_extendmap_timestep", "15", "Specifies how much many more minutes each extension makes", _, true, 5.0);
dvander@2168
   121
	g_Cvar_ExtendRoundStep = CreateConVar("sm_extendmap_roundstep", "5", "Specifies how many more rounds each extension makes", _, true, 1.0);
dvander@2168
   122
	g_Cvar_ExtendFragStep = CreateConVar("sm_extendmap_fragstep", "10", "Specifies how many more frags are allowed when map is extended.", _, true, 5.0);	
dvander@2168
   123
	g_Cvar_ExcludeMaps = CreateConVar("sm_mapvote_exclude", "5", "Specifies how many past maps to exclude from the vote.", _, true, 0.0);
dvander@2168
   124
	g_Cvar_IncludeMaps = CreateConVar("sm_mapvote_include", "5", "Specifies how many maps to include in the vote.", _, true, 2.0, true, 6.0);
dvander@2168
   125
	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);
dvander@2168
   126
	g_Cvar_Extend = CreateConVar("sm_mapvote_extend", "0", "Number of extensions allowed each map.", _, true, 0.0);
dvander@2168
   127
	g_Cvar_DontChange = CreateConVar("sm_mapvote_dontchange", "1", "Specifies if a 'Don't Change' option should be added to early votes", _, true, 0.0);
dvander@2168
   128
	g_Cvar_VoteDuration = CreateConVar("sm_mapvote_voteduration", "20", "Specifies how long the mapvote should be available for.", _, true, 5.0, true, 25.0);
dvander@2168
   129
	RegAdminCmd("sm_mapvote", Command_Mapvote, ADMFLAG_CHANGEMAP, "sm_mapvote - Forces MapChooser to attempt to run a map vote now.");
dvander@2168
   130
dvander@2168
   131
	g_Cvar_Winlimit = FindConVar("mp_winlimit");
dvander@2168
   132
	g_Cvar_Maxrounds = FindConVar("mp_maxrounds");
dvander@2168
   133
	g_Cvar_Fraglimit = FindConVar("mp_fraglimit");
dvander@2168
   134
	g_Cvar_Bonusroundtime = FindConVar("mp_bonusroundtime");
dvander@2168
   135
	
dvander@2168
   136
	if (g_Cvar_Winlimit != INVALID_HANDLE || g_Cvar_Maxrounds != INVALID_HANDLE)
dvander@2168
   137
	{
dvander@2168
   138
		HookEvent("round_end", Event_RoundEnd);
dvander@2168
   139
		HookEventEx("teamplay_win_panel", Event_TeamPlayWinPanel);
dvander@2168
   140
		HookEventEx("teamplay_restart_round", Event_TFRestartRound);
dvander@2168
   141
	}
dvander@2168
   142
	
dvander@2168
   143
	if (g_Cvar_Fraglimit != INVALID_HANDLE)
dvander@2168
   144
	{
dvander@2168
   145
		HookEvent("player_death", Event_PlayerDeath);		
dvander@2168
   146
	}
dvander@2168
   147
	
dvander@2168
   148
	AutoExecConfig(true, "mapchooser");
dvander@2168
   149
	
dvander@2168
   150
	//Change the mp_bonusroundtime max so that we have time to display the vote
dvander@2168
   151
	//If you display a vote during bonus time good defaults are 17 vote duration and 19 mp_bonustime
dvander@2168
   152
	if (g_Cvar_Bonusroundtime != INVALID_HANDLE)
dvander@2168
   153
	{
dvander@2168
   154
		SetConVarBounds(g_Cvar_Bonusroundtime, ConVarBound_Upper, true, 30.0);		
dvander@2168
   155
	}
dvander@2168
   156
	
dvander@2168
   157
dvander@2168
   158
	
dvander@2168
   159
	g_NominationsResetForward = CreateGlobalForward("OnNominationRemoved", ET_Ignore, Param_String, Param_Cell);
dvander@2168
   160
}
dvander@2168
   161
dvander@2168
   162
public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max)
dvander@2168
   163
{
dvander@2168
   164
	RegPluginLibrary("mapchooser");	
dvander@2168
   165
	
dvander@2168
   166
	CreateNative("NominateMap", Native_NominateMap);
dvander@2168
   167
	CreateNative("InitiateMapChooserVote", Native_InitiateVote);
dvander@2168
   168
	CreateNative("CanMapChooserStartVote", Native_CanVoteStart);
dvander@2168
   169
	CreateNative("HasEndOfMapVoteFinished", Native_CheckVoteDone);
dvander@2168
   170
	CreateNative("GetExcludeMapList", Native_GetExcludeMapList);
dvander@2168
   171
dvander@2168
   172
	return true;
dvander@2168
   173
}
dvander@2168
   174
dvander@2168
   175
public OnConfigsExecuted()
dvander@2168
   176
{
dvander@2168
   177
	if (ReadMapList(g_MapList,
dvander@2168
   178
					 g_mapFileSerial, 
dvander@2168
   179
					 "mapchooser",
dvander@2168
   180
					 MAPLIST_FLAG_CLEARARRAY|MAPLIST_FLAG_MAPSFOLDER)
dvander@2168
   181
		!= INVALID_HANDLE)
dvander@2168
   182
		
dvander@2168
   183
	{
dvander@2168
   184
		if (g_mapFileSerial == -1)
dvander@2168
   185
		{
dvander@2168
   186
			LogError("Unable to create a valid map list.");
dvander@2168
   187
		}
dvander@2168
   188
	}
dvander@2168
   189
	
dvander@2168
   190
	CreateNextVote();
dvander@2168
   191
	SetupTimeleftTimer();
dvander@2168
   192
	
dvander@2168
   193
	g_TotalRounds = 0;
dvander@2168
   194
	
dvander@2168
   195
	g_Extends = 0;
dvander@2168
   196
	
dvander@2168
   197
	g_MapVoteCompleted = false;
dvander@2168
   198
	
dvander@2168
   199
	g_NominateCount = 0;
dvander@2168
   200
	ClearArray(g_NominateList);
dvander@2168
   201
	ClearArray(g_NominateOwners);
dvander@2168
   202
	
dvander@2168
   203
	for (new i=0; i<MAXTEAMS; i++)
dvander@2168
   204
	{
dvander@2168
   205
		g_winCount[i] = 0;	
dvander@2168
   206
	}
dvander@2168
   207
	
dvander@2168
   208
dvander@2168
   209
	/* Check if mapchooser will attempt to start mapvote during bonus round time - TF2 Only */
dvander@2168
   210
	if ((g_Cvar_Bonusroundtime != INVALID_HANDLE) && !GetConVarInt(g_Cvar_StartRounds))
dvander@2168
   211
	{
dvander@2168
   212
		if (GetConVarFloat(g_Cvar_Bonusroundtime) <= GetConVarFloat(g_Cvar_VoteDuration))
dvander@2168
   213
		{
dvander@2168
   214
			LogError("Warning - Bonus Round Time shorter than Vote Time. Votes during bonus round may not have time to complete");
dvander@2168
   215
		}
dvander@2168
   216
	}
dvander@2168
   217
}
dvander@2168
   218
dvander@2168
   219
public OnMapEnd()
dvander@2168
   220
{
dvander@2168
   221
	g_HasVoteStarted = false;
dvander@2168
   222
	g_WaitingForVote = false;
dvander@2168
   223
	
dvander@2168
   224
	if (g_VoteTimer != INVALID_HANDLE)
dvander@2168
   225
	{
dvander@2168
   226
		KillTimer(g_VoteTimer);
dvander@2168
   227
		g_VoteTimer = INVALID_HANDLE;
dvander@2168
   228
	}
dvander@2168
   229
	
dvander@2168
   230
	if (g_RetryTimer != INVALID_HANDLE)
dvander@2168
   231
	{
dvander@2168
   232
		KillTimer(g_RetryTimer);
dvander@2168
   233
		g_RetryTimer = INVALID_HANDLE;
dvander@2168
   234
	}
dvander@2168
   235
	
dvander@2168
   236
	decl String:map[32];
dvander@2168
   237
	GetCurrentMap(map, sizeof(map));
dvander@2168
   238
	PushArrayString(g_OldMapList, map);
dvander@2168
   239
				
dvander@2168
   240
	if (GetArraySize(g_OldMapList) > GetConVarInt(g_Cvar_ExcludeMaps))
dvander@2168
   241
	{
dvander@2168
   242
		RemoveFromArray(g_OldMapList, 0);
dvander@2168
   243
	}	
dvander@2168
   244
}
dvander@2168
   245
dvander@2168
   246
public OnClientDisconnect(client)
dvander@2168
   247
{
dvander@2168
   248
	new index = FindValueInArray(g_NominateOwners, client);
dvander@2168
   249
	
dvander@2168
   250
	if (index == -1)
dvander@2168
   251
	{
dvander@2168
   252
		return;
dvander@2168
   253
	}
dvander@2168
   254
	
dvander@2168
   255
	new String:oldmap[33];
dvander@2168
   256
	GetArrayString(g_NominateList, index, oldmap, sizeof(oldmap));
dvander@2168
   257
	Call_StartForward(g_NominationsResetForward);
dvander@2168
   258
	Call_PushString(oldmap);
dvander@2168
   259
	Call_PushCell(GetArrayCell(g_NominateOwners, index));
dvander@2168
   260
	Call_Finish();
dvander@2168
   261
	
dvander@2168
   262
	RemoveFromArray(g_NominateOwners, index);
dvander@2168
   263
	RemoveFromArray(g_NominateList, index);
dvander@2168
   264
	g_NominateCount--;
dvander@2168
   265
}
dvander@2168
   266
dvander@2168
   267
public EndVoteChanged(Handle:convar, const String:oldValue[], const String:newValue[])
dvander@2168
   268
{
dvander@2168
   269
	if (newValue[0] == '1')
dvander@2168
   270
	{
dvander@2168
   271
		SetNextMap("Pending Vote");
dvander@2168
   272
	}
dvander@2168
   273
	else
dvander@2168
   274
	{
dvander@2168
   275
		SetNextMap("");	
dvander@2168
   276
	}
dvander@2168
   277
}
dvander@2168
   278
dvander@2168
   279
public OnMapTimeLeftChanged()
dvander@2168
   280
{
dvander@2168
   281
	if (GetArraySize(g_MapList))
dvander@2168
   282
	{
dvander@2168
   283
		SetupTimeleftTimer();
dvander@2168
   284
	}
dvander@2168
   285
}
dvander@2168
   286
dvander@2168
   287
SetupTimeleftTimer()
dvander@2168
   288
{
dvander@2168
   289
	new time;
dvander@2168
   290
	if (GetMapTimeLeft(time) && time > 0)
dvander@2168
   291
	{
dvander@2168
   292
		new startTime = GetConVarInt(g_Cvar_StartTime) * 60;
dvander@2168
   293
		if (time - startTime < 0 && GetConVarBool(g_Cvar_EndOfMapVote) && !g_MapVoteCompleted && !g_HasVoteStarted)
dvander@2168
   294
		{
dvander@2168
   295
			InitiateVote(MapChange_MapEnd, INVALID_HANDLE);		
dvander@2168
   296
		}
dvander@2168
   297
		else
dvander@2168
   298
		{
dvander@2168
   299
			if (g_VoteTimer != INVALID_HANDLE)
dvander@2168
   300
			{
dvander@2168
   301
				KillTimer(g_VoteTimer);
dvander@2168
   302
				g_VoteTimer = INVALID_HANDLE;
dvander@2168
   303
			}	
dvander@2168
   304
			
dvander@2168
   305
			g_VoteTimer = CreateTimer(float(time - startTime), Timer_StartMapVote);
dvander@2168
   306
		}		
dvander@2168
   307
	}
dvander@2168
   308
}
dvander@2168
   309
dvander@2168
   310
public Action:Timer_StartMapVote(Handle:timer)
dvander@2168
   311
{
dvander@2168
   312
	if (!GetArraySize(g_MapList) || !GetConVarBool(g_Cvar_EndOfMapVote) || g_MapVoteCompleted || g_HasVoteStarted)
dvander@2168
   313
	{
dvander@2168
   314
		return Plugin_Stop;
dvander@2168
   315
	}		
dvander@2168
   316
	
dvander@2168
   317
	if (timer == g_RetryTimer)
dvander@2168
   318
	{
dvander@2168
   319
		g_RetryTimer = INVALID_HANDLE;
dvander@2168
   320
	}
dvander@2168
   321
	else
dvander@2168
   322
	{
dvander@2168
   323
		g_VoteTimer = INVALID_HANDLE;
dvander@2168
   324
	}
dvander@2168
   325
	
dvander@2168
   326
	InitiateVote(MapChange_MapEnd, INVALID_HANDLE);
dvander@2168
   327
dvander@2168
   328
	return Plugin_Stop;
dvander@2168
   329
}
dvander@2168
   330
dvander@2168
   331
public Event_TFRestartRound(Handle:event, const String:name[], bool:dontBroadcast)
dvander@2168
   332
{
dvander@2168
   333
	/* Game got restarted - reset our round count tracking */
dvander@2168
   334
	g_TotalRounds = 0;	
dvander@2168
   335
}
dvander@2168
   336
dvander@2168
   337
public Event_TeamPlayWinPanel(Handle:event, const String:name[], bool:dontBroadcast)
dvander@2168
   338
{
dvander@2168
   339
	if (g_ChangeMapAtRoundEnd)
dvander@2168
   340
	{
dvander@2168
   341
		g_ChangeMapAtRoundEnd = false;
dvander@2168
   342
		CreateTimer(2.0, Timer_ChangeMap, INVALID_HANDLE);
dvander@2168
   343
	}
dvander@2168
   344
	
dvander@2168
   345
	if (!GetArraySize(g_MapList) || g_HasVoteStarted || g_MapVoteCompleted || !GetConVarBool(g_Cvar_EndOfMapVote))
dvander@2168
   346
	{
dvander@2168
   347
		return;
dvander@2168
   348
	}
dvander@2168
   349
	
dvander@2168
   350
	new bluescore = GetEventInt(event, "blue_score");
dvander@2168
   351
	new redscore = GetEventInt(event, "red_score");
dvander@2168
   352
	
dvander@2168
   353
	if(GetEventInt(event, "round_complete") == 1)
dvander@2168
   354
	{	
dvander@2168
   355
		switch(GetEventInt(event, "winning_team"))
dvander@2168
   356
		{
dvander@2168
   357
			case TFTeam_Blue:
dvander@2168
   358
			{
dvander@2168
   359
				CheckWinLimit(bluescore);
dvander@2168
   360
			}
dvander@2168
   361
			case TFTeam_Red:
dvander@2168
   362
			{
dvander@2168
   363
				CheckWinLimit(redscore);				
dvander@2168
   364
			}			
dvander@2168
   365
			//We need to do nothing on winning_team == 0 this indicates stalemate.
dvander@2168
   366
			default:
dvander@2168
   367
			{
dvander@2168
   368
				return;
dvander@2168
   369
			}			
dvander@2168
   370
		}
dvander@2168
   371
		
dvander@2168
   372
		g_TotalRounds++;
dvander@2168
   373
		CheckMaxRounds(g_TotalRounds);
dvander@2168
   374
	}
dvander@2168
   375
}
dvander@2168
   376
/* You ask, why don't you just use team_score event? And I answer... Because CSS doesn't. */
dvander@2168
   377
public Event_RoundEnd(Handle:event, const String:name[], bool:dontBroadcast)
dvander@2168
   378
{
dvander@2168
   379
	if (g_ChangeMapAtRoundEnd)
dvander@2168
   380
	{
dvander@2168
   381
		g_ChangeMapAtRoundEnd = false;
dvander@2168
   382
		CreateTimer(2.0, Timer_ChangeMap, INVALID_HANDLE);
dvander@2168
   383
	}
dvander@2168
   384
	
dvander@2168
   385
	if (!GetArraySize(g_MapList) || g_HasVoteStarted || g_MapVoteCompleted)
dvander@2168
   386
	{
dvander@2168
   387
		return;
dvander@2168
   388
	}
dvander@2168
   389
dvander@2168
   390
	new winner = GetEventInt(event, "winner");
dvander@2168
   391
	
dvander@2168
   392
	if (winner == 0 || winner == 1 || !GetConVarBool(g_Cvar_EndOfMapVote))
dvander@2168
   393
	{
dvander@2168
   394
		return;
dvander@2168
   395
	}
dvander@2168
   396
	
dvander@2168
   397
	if (winner >= MAXTEAMS)
dvander@2168
   398
	{
dvander@2168
   399
		SetFailState("Mod exceed maximum team count - Please file a bug report.");	
dvander@2168
   400
	}
dvander@2168
   401
dvander@2168
   402
	g_TotalRounds++;
dvander@2168
   403
	
dvander@2168
   404
	g_winCount[winner]++;
dvander@2168
   405
	
dvander@2168
   406
	CheckWinLimit(g_winCount[winner]);
dvander@2168
   407
	CheckMaxRounds(g_TotalRounds);
dvander@2168
   408
}
dvander@2168
   409
dvander@2168
   410
public CheckWinLimit(winner_score)
dvander@2168
   411
{	
dvander@2168
   412
	if (g_Cvar_Winlimit != INVALID_HANDLE)
dvander@2168
   413
	{
dvander@2168
   414
		new winlimit = GetConVarInt(g_Cvar_Winlimit);
dvander@2168
   415
		if (winlimit)
dvander@2168
   416
		{			
dvander@2168
   417
			if (winner_score >= (winlimit - GetConVarInt(g_Cvar_StartRounds)))
dvander@2168
   418
			{
dvander@2168
   419
				InitiateVote(MapChange_MapEnd, INVALID_HANDLE);
dvander@2168
   420
			}
dvander@2168
   421
		}
dvander@2168
   422
	}
dvander@2168
   423
}
dvander@2168
   424
dvander@2168
   425
public CheckMaxRounds(roundcount)
dvander@2168
   426
{		
dvander@2168
   427
	if (g_Cvar_Maxrounds != INVALID_HANDLE)
dvander@2168
   428
	{
dvander@2168
   429
		new maxrounds = GetConVarInt(g_Cvar_Maxrounds);
dvander@2168
   430
		if (maxrounds)
dvander@2168
   431
		{
dvander@2168
   432
			if (roundcount >= (maxrounds - GetConVarInt(g_Cvar_StartRounds)))
dvander@2168
   433
			{
dvander@2168
   434
				InitiateVote(MapChange_MapEnd, INVALID_HANDLE);
dvander@2168
   435
			}			
dvander@2168
   436
		}
dvander@2168
   437
	}
dvander@2168
   438
}
dvander@2168
   439
dvander@2168
   440
public Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)
dvander@2168
   441
{
dvander@2168
   442
	if (!GetArraySize(g_MapList) || g_Cvar_Fraglimit == INVALID_HANDLE || g_HasVoteStarted)
dvander@2168
   443
	{
dvander@2168
   444
		return;
dvander@2168
   445
	}
dvander@2168
   446
	
dvander@2168
   447
	if (!GetConVarInt(g_Cvar_Fraglimit) || !GetConVarBool(g_Cvar_EndOfMapVote))
dvander@2168
   448
	{
dvander@2168
   449
		return;
dvander@2168
   450
	}
dvander@2168
   451
dvander@2168
   452
	new fragger = GetClientOfUserId(GetEventInt(event, "attacker"));
dvander@2168
   453
	if (fragger && GetClientFrags(fragger) >= (GetConVarInt(g_Cvar_Fraglimit) - GetConVarInt(g_Cvar_StartFrags)))
dvander@2168
   454
	{
dvander@2168
   455
		InitiateVote(MapChange_MapEnd, INVALID_HANDLE);
dvander@2168
   456
	}
dvander@2168
   457
}
dvander@2168
   458
dvander@2168
   459
public Action:Command_Mapvote(client, args)
dvander@2168
   460
{
dvander@2168
   461
	InitiateVote(MapChange_MapEnd, INVALID_HANDLE);
dvander@2168
   462
dvander@2168
   463
	return Plugin_Handled;	
dvander@2168
   464
}
dvander@2168
   465
dvander@2168
   466
InitiateVote(MapChange:when, Handle:inputlist)
dvander@2168
   467
{
dvander@2168
   468
	if (!CanVoteStart())
dvander@2168
   469
	{
dvander@2168
   470
		return;
dvander@2168
   471
	}
dvander@2168
   472
	
dvander@2168
   473
	g_WaitingForVote = true;
dvander@2168
   474
	
dvander@2168
   475
	if (IsVoteInProgress())
dvander@2168
   476
	{
dvander@2168
   477
		// Can't start a vote, try again in 5 seconds.
dvander@2168
   478
		g_RetryTimer = CreateTimer(5.0, Timer_StartMapVote);
dvander@2168
   479
		return;
dvander@2168
   480
	}
dvander@2168
   481
	
dvander@2168
   482
	g_ChangeTime = when;
dvander@2168
   483
	
dvander@2168
   484
	g_WaitingForVote = false;
dvander@2168
   485
		
dvander@2168
   486
	g_HasVoteStarted = true;
dvander@2168
   487
	g_VoteMenu = CreateMenu(Handler_MapVoteMenu, MenuAction:MENU_ACTIONS_ALL);
dvander@2168
   488
	SetMenuTitle(g_VoteMenu, "Vote Nextmap");
dvander@2168
   489
	SetVoteResultCallback(g_VoteMenu, Handler_MapVoteFinished);
dvander@2168
   490
	
dvander@2168
   491
	/**
dvander@2168
   492
	 * TODO: Make a proper decision on when to clear the nominations list.
dvander@2168
   493
	 * Currently it clears when used, and stays if an external list is provided.
dvander@2168
   494
	 * Is this the right thing to do? External lists will probably come from places
dvander@2168
   495
	 * like sm_mapvote from the adminmenu in the future.
dvander@2168
   496
	 */
dvander@2168
   497
	 
dvander@2168
   498
	decl String:map[32];
dvander@2168
   499
	
dvander@2168
   500
	/* No input given - User our internal nominations and maplist */
dvander@2168
   501
	if (inputlist == INVALID_HANDLE)
dvander@2168
   502
	{
dvander@2168
   503
		new nominateCount = GetArraySize(g_NominateList);
dvander@2168
   504
		new voteSize = GetConVarInt(g_Cvar_IncludeMaps);
dvander@2168
   505
		
dvander@2168
   506
		/* Smaller of the two - It should be impossible for nominations to exceed the size though (cvar changed mid-map?) */
dvander@2168
   507
		new nominationsToAdd = nominateCount >= voteSize ? voteSize : nominateCount;
dvander@2168
   508
		
dvander@2168
   509
		
dvander@2168
   510
		for (new i=0; i<nominationsToAdd; i++)
dvander@2168
   511
		{
dvander@2168
   512
			GetArrayString(g_NominateList, i, map, sizeof(map));
dvander@2168
   513
			AddMenuItem(g_VoteMenu, map, map);
dvander@2168
   514
			
dvander@2168
   515
			/* Notify Nominations that this map is now free */
dvander@2168
   516
			Call_StartForward(g_NominationsResetForward);
dvander@2168
   517
			Call_PushString(map);
dvander@2168
   518
			Call_PushCell(GetArrayCell(g_NominateOwners, i));
dvander@2168
   519
			Call_Finish();
dvander@2168
   520
		}
dvander@2168
   521
		
dvander@2168
   522
		/* Clear out the rest of the nominations array */
dvander@2168
   523
		for (new i=nominationsToAdd; i<nominateCount; i++)
dvander@2168
   524
		{
dvander@2168
   525
			GetArrayString(g_NominateList, i, map, sizeof(map));
dvander@2168
   526
			
dvander@2168
   527
			/* Notify Nominations that this map is now free */
dvander@2168
   528
			Call_StartForward(g_NominationsResetForward);
dvander@2168
   529
			Call_PushString(map);
dvander@2168
   530
			Call_PushCell(GetArrayCell(g_NominateOwners, i));
dvander@2168
   531
			Call_Finish();			
dvander@2168
   532
		}
dvander@2168
   533
		
dvander@2168
   534
		/* There should currently be 'nominationsToAdd' unique maps in the vote */
dvander@2168
   535
		
dvander@2168
   536
		new i = nominationsToAdd;
dvander@2168
   537
		new count = 0;
dvander@2168
   538
		new availableMaps = GetArraySize(g_NextMapList);
dvander@2168
   539
		
dvander@2168
   540
		while (i < voteSize)
dvander@2168
   541
		{
dvander@2168
   542
			GetArrayString(g_NextMapList, count, map, sizeof(map));
dvander@2168
   543
			count++;
dvander@2168
   544
			
dvander@2168
   545
			//Check if this map is in the nominate list (and thus already in the vote) */
dvander@2168
   546
			if (FindStringInArray(g_NominateList, map) == -1)
dvander@2168
   547
			{
dvander@2168
   548
				/* Insert the map and increment our count */
dvander@2168
   549
				AddMenuItem(g_VoteMenu, map, map);
dvander@2168
   550
				i++;
dvander@2168
   551
			}
dvander@2168
   552
			
dvander@2168
   553
			if (count >= availableMaps)
dvander@2168
   554
			{
dvander@2168
   555
				//Run out of maps, this will have to do.
dvander@2168
   556
				break;	
dvander@2168
   557
			}
dvander@2168
   558
		}
dvander@2168
   559
		
dvander@2168
   560
		/* Wipe out our nominations list - Nominations have already been informed of this */
dvander@2168
   561
		ClearArray(g_NominateOwners);
dvander@2168
   562
		ClearArray(g_NominateList);
dvander@2168
   563
	}
dvander@2168
   564
	else //We were given a list of maps to start the vote with
dvander@2168
   565
	{
dvander@2168
   566
		new size = GetArraySize(inputlist);
dvander@2168
   567
		
dvander@2168
   568
		for (new i=0; i<size; i++)
dvander@2168
   569
		{
dvander@2168
   570
			GetArrayString(inputlist, i, map, sizeof(map));
dvander@2168
   571
			
dvander@2168
   572
			if (IsMapValid(map))
dvander@2168
   573
			{
dvander@2168
   574
				AddMenuItem(g_VoteMenu, map, map);
dvander@2168
   575
			}	
dvander@2168
   576
		}
dvander@2168
   577
	}
dvander@2168
   578
	
dvander@2168
   579
	/* Do we add any special items? */
dvander@2168
   580
	if ((when == MapChange_Instant || when == MapChange_RoundEnd) && GetConVarBool(g_Cvar_DontChange))
dvander@2168
   581
	{
dvander@2168
   582
		AddMenuItem(g_VoteMenu, VOTE_DONTCHANGE, "Don't Change");
dvander@2168
   583
	}
dvander@2168
   584
	else if (GetConVarBool(g_Cvar_Extend) && g_Extends < GetConVarInt(g_Cvar_Extend))
dvander@2168
   585
	{
dvander@2168
   586
		AddMenuItem(g_VoteMenu, VOTE_EXTEND, "Extend Map");
dvander@2168
   587
	}
dvander@2168
   588
	
dvander@2168
   589
	new voteDuration = GetConVarInt(g_Cvar_VoteDuration);
dvander@2168
   590
dvander@2168
   591
	SetMenuExitButton(g_VoteMenu, false);
dvander@2168
   592
	VoteMenuToAll(g_VoteMenu, voteDuration);
dvander@2168
   593
dvander@2168
   594
	LogMessage("Voting for next map has started.");
dvander@2168
   595
	PrintToChatAll("[SM] %t", "Nextmap Voting Started");
dvander@2168
   596
}
dvander@2168
   597
dvander@2168
   598
public Handler_MapVoteFinished(Handle:menu,
dvander@2168
   599
						   num_votes, 
dvander@2168
   600
						   num_clients,
dvander@2168
   601
						   const client_info[][2], 
dvander@2168
   602
						   num_items,
dvander@2168
   603
						   const item_info[][2])
dvander@2168
   604
{
dvander@2168
   605
	if (num_votes == 0)
dvander@2168
   606
	{
dvander@2168
   607
		LogError("No Votes recorded yet Advanced callback fired - Tell pRED* to fix this");
dvander@2168
   608
		return;	
dvander@2168
   609
	}
dvander@2168
   610
	
dvander@2168
   611
	decl String:map[32];
dvander@2168
   612
	GetMenuItem(menu, item_info[0][VOTEINFO_ITEM_INDEX], map, sizeof(map));
dvander@2168
   613
dvander@2168
   614
	if (strcmp(map, VOTE_EXTEND, false) == 0)
dvander@2168
   615
	{
dvander@2168
   616
		g_Extends++;
dvander@2168
   617
		
dvander@2168
   618
		new time;
dvander@2168
   619
		if (GetMapTimeLimit(time))
dvander@2168
   620
		{
dvander@2168
   621
			if (time > 0)
dvander@2168
   622
			{
dvander@2168
   623
				ExtendMapTimeLimit(GetConVarInt(g_Cvar_ExtendTimeStep)*60);						
dvander@2168
   624
			}
dvander@2168
   625
		}
dvander@2168
   626
		
dvander@2168
   627
		if (g_Cvar_Winlimit != INVALID_HANDLE)
dvander@2168
   628
		{
dvander@2168
   629
			new winlimit = GetConVarInt(g_Cvar_Winlimit);
dvander@2168
   630
			if (winlimit)
dvander@2168
   631
			{
dvander@2168
   632
				SetConVarInt(g_Cvar_Winlimit, winlimit + GetConVarInt(g_Cvar_ExtendRoundStep));
dvander@2168
   633
			}					
dvander@2168
   634
		}
dvander@2168
   635
		
dvander@2168
   636
		if (g_Cvar_Maxrounds != INVALID_HANDLE)
dvander@2168
   637
		{
dvander@2168
   638
			new maxrounds = GetConVarInt(g_Cvar_Maxrounds);
dvander@2168
   639
			if (maxrounds)
dvander@2168
   640
			{
dvander@2168
   641
				SetConVarInt(g_Cvar_Maxrounds, maxrounds + GetConVarInt(g_Cvar_ExtendRoundStep));
dvander@2168
   642
			}
dvander@2168
   643
		}
dvander@2168
   644
		
dvander@2168
   645
		if (g_Cvar_Fraglimit != INVALID_HANDLE)
dvander@2168
   646
		{
dvander@2168
   647
			new fraglimit = GetConVarInt(g_Cvar_Fraglimit);
dvander@2168
   648
			if (fraglimit)
dvander@2168
   649
			{
dvander@2168
   650
				SetConVarInt(g_Cvar_Fraglimit, fraglimit + GetConVarInt(g_Cvar_ExtendFragStep));						
dvander@2168
   651
			}
dvander@2168
   652
		}
dvander@2168
   653
dvander@2168
   654
		PrintToChatAll("[SM] %t", "Current Map Extended", RoundToFloor(float(item_info[0][VOTEINFO_ITEM_VOTES])/float(num_votes)*100), num_votes);
dvander@2168
   655
		LogMessage("Voting for next map has finished. The current map has been extended.");
dvander@2168
   656
		
dvander@2168
   657
		// We extended, so we'll have to vote again.
dvander@2168
   658
		g_HasVoteStarted = false;
dvander@2168
   659
		CreateNextVote();
dvander@2168
   660
		SetupTimeleftTimer();
dvander@2168
   661
		
dvander@2168
   662
	}
dvander@2168
   663
	else if (strcmp(map, VOTE_DONTCHANGE, false) == 0)
dvander@2168
   664
	{
dvander@2168
   665
		PrintToChatAll("[SM] %t", "Current Map Stays", RoundToFloor(float(item_info[0][VOTEINFO_ITEM_VOTES])/float(num_votes)*100), num_votes);
dvander@2168
   666
		LogMessage("Voting for next map has finished. 'No Change' was the winner");
dvander@2168
   667
		
dvander@2168
   668
		g_HasVoteStarted = false;
dvander@2168
   669
		CreateNextVote();
dvander@2168
   670
		SetupTimeleftTimer();
dvander@2168
   671
	}
dvander@2168
   672
	else
dvander@2168
   673
	{
dvander@2168
   674
		if (g_ChangeTime == MapChange_MapEnd)
dvander@2168
   675
		{
dvander@2168
   676
			SetNextMap(map);
dvander@2168
   677
		}
dvander@2168
   678
		else if (g_ChangeTime == MapChange_Instant)
dvander@2168
   679
		{
dvander@2168
   680
			new Handle:data;
dvander@2168
   681
			CreateDataTimer(2.0, Timer_ChangeMap, data);
dvander@2168
   682
			WritePackString(data, map);
dvander@2168
   683
		}
dvander@2168
   684
		else // MapChange_RoundEnd
dvander@2168
   685
		{
dvander@2168
   686
			SetNextMap(map);
dvander@2168
   687
			g_ChangeMapAtRoundEnd = true;
dvander@2168
   688
		}
dvander@2168
   689
		
dvander@2168
   690
		g_HasVoteStarted = false;
dvander@2168
   691
		g_MapVoteCompleted = true;
dvander@2168
   692
		
dvander@2168
   693
		PrintToChatAll("[SM] %t", "Nextmap Voting Finished", map, RoundToFloor(float(item_info[0][VOTEINFO_ITEM_VOTES])/float(num_votes)*100), num_votes);
dvander@2168
   694
		LogMessage("Voting for next map has finished. Nextmap: %s.", map);
dvander@2168
   695
	}	
dvander@2168
   696
}
dvander@2168
   697
dvander@2168
   698
public Handler_MapVoteMenu(Handle:menu, MenuAction:action, param1, param2)
dvander@2168
   699
{
dvander@2168
   700
	switch (action)
dvander@2168
   701
	{
dvander@2168
   702
		case MenuAction_End:
dvander@2168
   703
		{
dvander@2168
   704
			g_VoteMenu = INVALID_HANDLE;
dvander@2168
   705
			CloseHandle(menu);
dvander@2168
   706
		}
dvander@2168
   707
		
dvander@2168
   708
		case MenuAction_Display:
dvander@2168
   709
		{
dvander@2168
   710
	 		decl String:buffer[255];
dvander@2168
   711
			Format(buffer, sizeof(buffer), "%T", "Vote Nextmap", param1);
dvander@2168
   712
dvander@2168
   713
			new Handle:panel = Handle:param2;
dvander@2168
   714
			SetPanelTitle(panel, buffer);
dvander@2168
   715
		}		
dvander@2168
   716
		
dvander@2168
   717
		case MenuAction_DisplayItem:
dvander@2168
   718
		{
dvander@2168
   719
			if (GetMenuItemCount(menu) - 1 == param2)
dvander@2168
   720
			{
dvander@2168
   721
				decl String:map[64], String:buffer[255];
dvander@2168
   722
				GetMenuItem(menu, param2, map, sizeof(map));
dvander@2168
   723
				if (strcmp(map, VOTE_EXTEND, false) == 0)
dvander@2168
   724
				{
dvander@2168
   725
					Format(buffer, sizeof(buffer), "%T", "Extend Map", param1);
dvander@2168
   726
					return RedrawMenuItem(buffer);
dvander@2168
   727
				}
dvander@2168
   728
				else if (strcmp(map, VOTE_DONTCHANGE, false) == 0)
dvander@2168
   729
				{
dvander@2168
   730
					Format(buffer, sizeof(buffer), "%T", "Dont Change", param1);
dvander@2168
   731
					return RedrawMenuItem(buffer);					
dvander@2168
   732
				}
dvander@2168
   733
			}
dvander@2168
   734
		}		
dvander@2168
   735
	
dvander@2168
   736
		case MenuAction_VoteCancel:
dvander@2168
   737
		{
dvander@2168
   738
			// If we receive 0 votes, pick at random.
dvander@2168
   739
			if (param1 == VoteCancel_NoVotes && GetConVarBool(g_Cvar_NoVoteMode))
dvander@2168
   740
			{
dvander@2168
   741
				new count = GetMenuItemCount(menu);
dvander@2168
   742
				new item = GetRandomInt(0, count - 1);
dvander@2168
   743
				decl String:map[32];
dvander@2168
   744
				GetMenuItem(menu, item, map, sizeof(map));
dvander@2168
   745
				
dvander@2168
   746
				while (strcmp(map, VOTE_EXTEND, false) == 0)
dvander@2168
   747
				{
dvander@2168
   748
					item = GetRandomInt(0, count - 1);
dvander@2168
   749
					GetMenuItem(menu, item, map, sizeof(map));
dvander@2168
   750
				}
dvander@2168
   751
				
dvander@2168
   752
				SetNextMap(map);			
dvander@2168
   753
			}
dvander@2168
   754
			else
dvander@2168
   755
			{
dvander@2168
   756
				// We were actually cancelled. What should we do?
dvander@2168
   757
				g_HasVoteStarted = false;
dvander@2168
   758
				CreateNextVote();
dvander@2168
   759
				SetupTimeleftTimer();
dvander@2168
   760
			}
dvander@2168
   761
		}
dvander@2168
   762
	}
dvander@2168
   763
	
dvander@2168
   764
	return 0;
dvander@2168
   765
}
dvander@2168
   766
dvander@2168
   767
public Action:Timer_ChangeMap(Handle:hTimer, Handle:dp)
dvander@2168
   768
{
dvander@2168
   769
	new String:map[65];
dvander@2168
   770
	
dvander@2168
   771
	if (dp == INVALID_HANDLE)
dvander@2168
   772
	{
dvander@2168
   773
		if (!GetNextMap(map, sizeof(map)))
dvander@2168
   774
		{
dvander@2168
   775
			//No passed map and no set nextmap. fail!
dvander@2168
   776
			return Plugin_Stop;	
dvander@2168
   777
		}
dvander@2168
   778
	}
dvander@2168
   779
	else
dvander@2168
   780
	{
dvander@2168
   781
		ResetPack(dp);
dvander@2168
   782
		ReadPackString(dp, map, sizeof(map));		
dvander@2168
   783
	}
dvander@2168
   784
	
dvander@2168
   785
	ServerCommand("changelevel \"%s\"", map);
dvander@2168
   786
	
dvander@2168
   787
	return Plugin_Stop;
dvander@2168
   788
}
dvander@2168
   789
dvander@2168
   790
CreateNextVote()
dvander@2168
   791
{
dvander@2168
   792
	if(g_NextMapList != INVALID_HANDLE)
dvander@2168
   793
	{
dvander@2168
   794
		ClearArray(g_NextMapList);
dvander@2168
   795
	}
dvander@2168
   796
	
dvander@2168
   797
	decl String:map[32];
dvander@2168
   798
	new index, Handle:tempMaps  = CloneArray(g_MapList);
dvander@2168
   799
	
dvander@2168
   800
	GetCurrentMap(map, sizeof(map));
dvander@2168
   801
	index = FindStringInArray(tempMaps, map);
dvander@2168
   802
	if (index != -1)
dvander@2168
   803
	{
dvander@2168
   804
		RemoveFromArray(tempMaps, index);
dvander@2168
   805
	}	
dvander@2168
   806
	
dvander@2168
   807
	if (GetConVarInt(g_Cvar_ExcludeMaps) && GetArraySize(tempMaps) > GetConVarInt(g_Cvar_ExcludeMaps))
dvander@2168
   808
	{
dvander@2168
   809
		for (new i = 0; i < GetArraySize(g_OldMapList); i++)
dvander@2168
   810
		{
dvander@2168
   811
			GetArrayString(g_OldMapList, i, map, sizeof(map));
dvander@2168
   812
			index = FindStringInArray(tempMaps, map);
dvander@2168
   813
			if (index != -1)
dvander@2168
   814
			{
dvander@2168
   815
				RemoveFromArray(tempMaps, index);
dvander@2168
   816
			}
dvander@2168
   817
		}	
dvander@2168
   818
	}
dvander@2168
   819
dvander@2168
   820
	new limit = (GetConVarInt(g_Cvar_IncludeMaps) < GetArraySize(tempMaps) ? GetConVarInt(g_Cvar_IncludeMaps) : GetArraySize(tempMaps));
dvander@2168
   821
	for (new i = 0; i < limit; i++)
dvander@2168
   822
	{
dvander@2168
   823
		new b = GetRandomInt(0, GetArraySize(tempMaps) - 1);
dvander@2168
   824
		GetArrayString(tempMaps, b, map, sizeof(map));		
dvander@2168
   825
		PushArrayString(g_NextMapList, map);
dvander@2168
   826
		RemoveFromArray(tempMaps, b);
dvander@2168
   827
	}
dvander@2168
   828
	
dvander@2168
   829
	CloseHandle(tempMaps);
dvander@2168
   830
}
dvander@2168
   831
dvander@2168
   832
bool:CanVoteStart()
dvander@2168
   833
{
dvander@2168
   834
	if (g_WaitingForVote || g_HasVoteStarted)
dvander@2168
   835
	{
dvander@2168
   836
		return false;	
dvander@2168
   837
	}
dvander@2168
   838
	
dvander@2168
   839
	return true;
dvander@2168
   840
}
dvander@2168
   841
dvander@2168
   842
NominateResult:InternalNominateMap(String:map[], bool:force, owner)
dvander@2168
   843
{
dvander@2168
   844
	if (!IsMapValid(map))
dvander@2168
   845
	{
dvander@2168
   846
		return Nominate_InvalidMap;
dvander@2168
   847
	}
dvander@2168
   848
	
dvander@2168
   849
	new index;
dvander@2168
   850
dvander@2168
   851
	if ((index = FindValueInArray(g_NominateOwners, owner)) != -1)
dvander@2168
   852
	{
dvander@2168
   853
		new String:oldmap[33];
dvander@2168
   854
		GetArrayString(g_NominateList, index, oldmap, sizeof(oldmap));
dvander@2168
   855
		Call_StartForward(g_NominationsResetForward);
dvander@2168
   856
		Call_PushString(oldmap);
dvander@2168
   857
		Call_PushCell(owner);
dvander@2168
   858
		Call_Finish();
dvander@2168
   859
		
dvander@2168
   860
		
dvander@2168
   861
		SetArrayString(g_NominateList, index, map);
dvander@2168
   862
		return Nominate_Replaced;
dvander@2168
   863
	}
dvander@2168
   864
	
dvander@2168
   865
	/* Too many nominated maps. */
dvander@2168
   866
	if (g_NominateCount >= GetConVarInt(g_Cvar_IncludeMaps) && !force)
dvander@2168
   867
	{
dvander@2168
   868
		return Nominate_VoteFull;
dvander@2168
   869
	}
dvander@2168
   870
	
dvander@2168
   871
	/* Map already in the vote */
dvander@2168
   872
	if (FindStringInArray(g_NominateList, map) != -1)
dvander@2168
   873
	{
dvander@2168
   874
		return Nominate_AlreadyInVote;	
dvander@2168
   875
	}
dvander@2168
   876
	
dvander@2168
   877
	
dvander@2168
   878
	PushArrayString(g_NominateList, map);
dvander@2168
   879
	PushArrayCell(g_NominateOwners, owner);
dvander@2168
   880
	g_NominateCount++;
dvander@2168
   881
	
dvander@2168
   882
	while (GetArraySize(g_NominateList) > GetConVarInt(g_Cvar_IncludeMaps))
dvander@2168
   883
	{
dvander@2168
   884
		new String:oldmap[33];
dvander@2168
   885
		GetArrayString(g_NominateList, 0, oldmap, sizeof(oldmap));
dvander@2168
   886
		Call_StartForward(g_NominationsResetForward);
dvander@2168
   887
		Call_PushString(oldmap);
dvander@2168
   888
		Call_PushCell(GetArrayCell(g_NominateOwners, 0));
dvander@2168
   889
		Call_Finish();
dvander@2168
   890
		
dvander@2168
   891
		RemoveFromArray(g_NominateList, 0);
dvander@2168
   892
		RemoveFromArray(g_NominateOwners, 0);
dvander@2168
   893
	}
dvander@2168
   894
	
dvander@2168
   895
	return Nominate_Added;
dvander@2168
   896
}
dvander@2168
   897
dvander@2168
   898
/* Add natives to allow nominate and initiate vote to be call */
dvander@2168
   899
dvander@2168
   900
/* native  bool:NominateMap(const String:map[], bool:force, &NominateError:error); */
dvander@2168
   901
public Native_NominateMap(Handle:plugin, numParams)
dvander@2168
   902
{
dvander@2168
   903
	new len;
dvander@2168
   904
	GetNativeStringLength(1, len);
dvander@2168
   905
	
dvander@2168
   906
	if (len <= 0)
dvander@2168
   907
	{
dvander@2168
   908
	  return false;
dvander@2168
   909
	}
dvander@2168
   910
	
dvander@2168
   911
	new String:map[len+1];
dvander@2168
   912
	GetNativeString(1, map, len+1);
dvander@2168
   913
	
dvander@2168
   914
	return _:InternalNominateMap(map, GetNativeCell(2), GetNativeCell(3));
dvander@2168
   915
}
dvander@2168
   916
dvander@2168
   917
/* native InitiateMapChooserVote(); */
dvander@2168
   918
public Native_InitiateVote(Handle:plugin, numParams)
dvander@2168
   919
{
dvander@2168
   920
	new MapChange:when = MapChange:GetNativeCell(1);
dvander@2168
   921
	new Handle:inputarray = Handle:GetNativeCell(2);
dvander@2168
   922
	
dvander@2168
   923
	LogMessage("Starting map vote because outside request");
dvander@2168
   924
	InitiateVote(when, inputarray);
dvander@2168
   925
}
dvander@2168
   926
dvander@2168
   927
public Native_CanVoteStart(Handle:plugin, numParams)
dvander@2168
   928
{
dvander@2168
   929
	return CanVoteStart();	
dvander@2168
   930
}
dvander@2168
   931
dvander@2168
   932
public Native_CheckVoteDone(Handle:plugin, numParams)
dvander@2168
   933
{
dvander@2168
   934
	return g_MapVoteCompleted;
dvander@2168
   935
}
dvander@2168
   936
dvander@2168
   937
public Native_GetExcludeMapList(Handle:plugin, numParams)
dvander@2168
   938
{
dvander@2168
   939
	new Handle:array = Handle:GetNativeCell(1);
dvander@2168
   940
	
dvander@2168
   941
	if (array == INVALID_HANDLE)
dvander@2168
   942
	{
dvander@2168
   943
		return;	
dvander@2168
   944
	}
dvander@2168
   945
	
dvander@2168
   946
	
dvander@2168
   947
	new size = GetArraySize(g_OldMapList);
dvander@2168
   948
	decl String:map[33];
dvander@2168
   949
	
dvander@2168
   950
	for (new i=0; i<size; i++)
dvander@2168
   951
	{
dvander@2168
   952
		GetArrayString(g_OldMapList, i, map, sizeof(map));
dvander@2168
   953
		PushArrayString(array, map);	
dvander@2168
   954
	}
dvander@2168
   955
	
dvander@2168
   956
	return;
dvander@2168
   957
}