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