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