core/MenuVoting.cpp
author Asher Baker <asherkin@gmail.com>
Thu May 16 14:58:14 2013 +0100 (2013-05-16)
changeset 3920 e4fa6b583893
parent 3505 5fa96c27eab9
permissions -rw-r--r--
Fixed copy-paste error in 116256b519b5.
dvander@1269
     1
/**
dvander@2737
     2
 * vim: set ts=4 sw=4 :
ds@1330
     3
 * =============================================================================
dvander@1269
     4
 * SourceMod
dvander@2737
     5
 * Copyright (C) 2004-2009 AlliedModders LLC.  All rights reserved.
ds@1330
     6
 * =============================================================================
dvander@1269
     7
 *
ds@1330
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1330
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330
    10
 * Free Software Foundation.
dvander@1269
    11
 * 
ds@1330
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1330
    15
 * details.
dvander@1269
    16
 *
ds@1330
    17
 * You should have received a copy of the GNU General Public License along with
ds@1330
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1269
    19
 *
ds@1330
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1330
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1330
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1330
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@1269
    28
 *
dvander@1269
    29
 * Version: $Id$
dvander@1269
    30
 */
dvander@1269
    31
dvander@1269
    32
#include <string.h>
dvander@1269
    33
#include <stdlib.h>
dvander@1269
    34
#include "MenuVoting.h"
dvander@1269
    35
#include "PlayerManager.h"
dvander@1269
    36
#include "sourcemm_api.h"
pred@2801
    37
#include <sourcemod.h>
pred@2801
    38
#include <Logger.h>
pred@2801
    39
#include <HalfLife2.h>
pred@2801
    40
#include <mathlib.h>
pred@2801
    41
#include <const.h>
dvander@3004
    42
#include <ITranslator.h>
dvander@3004
    43
#include "logic_bridge.h"
dvander@1269
    44
dvander@1291
    45
float g_next_vote = 0.0f;
dvander@1291
    46
pred@2801
    47
#define VOTE_NOT_VOTING -2
pred@2801
    48
#define VOTE_PENDING -1
pred@2801
    49
pred@2801
    50
ConVar sm_vote_hintbox("sm_vote_progress_hintbox", 
pred@2801
    51
					   "0", 
pred@2801
    52
					   0, 
pred@2801
    53
					   "Show current vote progress in a hint box",
pred@2801
    54
					   true,
pred@2801
    55
					   0.0,
pred@2801
    56
					   true,
pred@2801
    57
					   1.0);
pred@2801
    58
pred@2801
    59
ConVar sm_vote_chat("sm_vote_progress_chat", 
pred@2801
    60
					   "0", 
pred@2801
    61
					   0, 
pred@2801
    62
					   "Show current vote progress as chat messages",
pred@2801
    63
					   true,
pred@2801
    64
					   0.0,
pred@2801
    65
					   true,
pred@2801
    66
					   1.0);
pred@2801
    67
pred@2801
    68
ConVar sm_vote_console("sm_vote_progress_console", 
pred@2801
    69
					   "0", 
pred@2801
    70
					   0, 
pred@2801
    71
					   "Show current vote progress as console messages",
pred@2801
    72
					   true,
pred@2801
    73
					   0.0,
pred@2801
    74
					   true,
pred@2801
    75
					   1.0);
pred@2801
    76
pred@2801
    77
ConVar sm_vote_client_console("sm_vote_progress_client_console", 
pred@2801
    78
					   "0", 
pred@2801
    79
					   0, 
pred@2801
    80
					   "Show current vote progress as console messages to clients",
pred@2801
    81
					   true,
pred@2801
    82
					   0.0,
pred@2801
    83
					   true,
pred@2801
    84
					   1.0);
pred@2801
    85
pred@2801
    86
ds@2400
    87
#if SOURCE_ENGINE >= SE_ORANGEBOX
faluco@1541
    88
void OnVoteDelayChange(IConVar *cvar, const char *value, float flOldValue);
faluco@1541
    89
#else
dvander@1291
    90
void OnVoteDelayChange(ConVar *cvar, const char *value);
faluco@1541
    91
#endif
dvander@1291
    92
ConVar sm_vote_delay("sm_vote_delay",
dvander@1291
    93
					 "30",
dvander@1291
    94
					 0,
dvander@1291
    95
					 "Sets the recommended time in between public votes",
dvander@1291
    96
					 false,
dvander@1291
    97
					 0.0,
dvander@1291
    98
					 false,
dvander@1291
    99
					 0.0,
dvander@1291
   100
					 OnVoteDelayChange);
dvander@1291
   101
ds@2400
   102
#if SOURCE_ENGINE >= SE_ORANGEBOX
faluco@1541
   103
void OnVoteDelayChange(IConVar *cvar, const char *value, float flOldValue)
faluco@1541
   104
#else
dvander@1291
   105
void OnVoteDelayChange(ConVar *cvar, const char *value)
faluco@1541
   106
#endif
dvander@1291
   107
{
dvander@1291
   108
	/* See if the new vote delay isn't something we need to account for */
dvander@1291
   109
	if (sm_vote_delay.GetFloat() < 1.0f)
dvander@1291
   110
	{
dvander@1291
   111
		g_next_vote = 0.0f;
dvander@1291
   112
		return;
dvander@1291
   113
	}
dvander@1291
   114
dvander@1291
   115
	/* If there was never a last vote, ignore this change */
dvander@1291
   116
	if (g_next_vote < 0.1f)
dvander@1291
   117
	{
dvander@1291
   118
		return;
dvander@1291
   119
	}
dvander@1291
   120
dvander@1291
   121
	/* Subtract the original value, then add the new one. */
dvander@1291
   122
	g_next_vote -= (float)atof(value);
dvander@1291
   123
	g_next_vote += sm_vote_delay.GetFloat();
dvander@1291
   124
}
dvander@1291
   125
dvander@1291
   126
unsigned int VoteMenuHandler::GetRemainingVoteDelay()
dvander@1291
   127
{
dvander@1291
   128
	if (g_next_vote <= gpGlobals->curtime)
dvander@1291
   129
	{
dvander@1291
   130
		return 0;
dvander@1291
   131
	}
dvander@1291
   132
dvander@1291
   133
	return (unsigned int)(g_next_vote - gpGlobals->curtime);
dvander@1291
   134
}
dvander@1291
   135
dvander@1269
   136
void VoteMenuHandler::OnSourceModAllInitialized()
dvander@1269
   137
{
dvander@1269
   138
	g_Players.AddClientListener(this);
dvander@1269
   139
}
dvander@1269
   140
dvander@1269
   141
void VoteMenuHandler::OnSourceModShutdown()
dvander@1269
   142
{
dvander@1269
   143
	g_Players.RemoveClientListener(this);
dvander@1269
   144
}
dvander@1269
   145
dvander@1291
   146
void VoteMenuHandler::OnSourceModLevelChange(const char *mapName)
dvander@1291
   147
{
dvander@1291
   148
	g_next_vote = 0.0f;
dvander@1291
   149
}
dvander@1291
   150
dvander@1269
   151
unsigned int VoteMenuHandler::GetMenuAPIVersion2()
dvander@1269
   152
{
dvander@1269
   153
	return m_pHandler->GetMenuAPIVersion2();
dvander@1269
   154
}
dvander@1269
   155
dvander@1269
   156
void VoteMenuHandler::OnClientDisconnected(int client)
dvander@1269
   157
{
dvander@1269
   158
	if (!IsVoteInProgress())
dvander@1269
   159
	{
dvander@1269
   160
		return;
dvander@1269
   161
	}
dvander@1269
   162
dvander@2056
   163
	/* Wipe out their vote if they had one.  We have to make sure the the the
dvander@2056
   164
	 * newly connected client is not allowed to vote. 
dvander@2056
   165
	 */
dvander@1269
   166
	int item;
pred@2801
   167
	if ((item = m_ClientVotes[client]) >= VOTE_PENDING)
dvander@1269
   168
	{
dvander@2056
   169
		if (item >= 0)
dvander@2056
   170
		{
dvander@2056
   171
			assert((unsigned)item < m_Items);
dvander@2056
   172
			assert(m_Votes[item] > 0);
dvander@2056
   173
			m_Votes[item]--;
dvander@2056
   174
		}
pred@2801
   175
		m_ClientVotes[client] = VOTE_NOT_VOTING;
dvander@1269
   176
	}
dvander@1269
   177
}
dvander@1269
   178
dvander@1269
   179
bool VoteMenuHandler::IsVoteInProgress()
dvander@1269
   180
{
dvander@1269
   181
	return (m_pCurMenu != NULL);
dvander@1269
   182
}
dvander@1269
   183
dvander@2056
   184
bool VoteMenuHandler::StartVote(IBaseMenu *menu,
dvander@2056
   185
								unsigned int num_clients,
dvander@2056
   186
								int clients[],
dvander@2056
   187
								unsigned int max_time,
dvander@2056
   188
								unsigned int flags/* =0 */)
dvander@1269
   189
{
dvander@1269
   190
	if (!InitializeVoting(menu, menu->GetHandler(), max_time, flags))
dvander@1269
   191
	{
dvander@1269
   192
		return false;
dvander@1269
   193
	}
dvander@1269
   194
dvander@2056
   195
	/* Note: we can use game time and not universal time because 
dvander@2056
   196
	 * if we're voting then players are in-game.
dvander@2056
   197
	 */
dvander@2056
   198
dvander@1291
   199
	float fVoteDelay = sm_vote_delay.GetFloat();
dvander@1291
   200
	if (fVoteDelay < 1.0)
dvander@1291
   201
	{
dvander@1291
   202
		g_next_vote = 0.0;
dvander@2056
   203
	}
dvander@2056
   204
	else
dvander@2056
   205
	{
dvander@1291
   206
		/* This little trick breaks for infinite votes!
dvander@1291
   207
		 * However, we just ignore that since those 1) shouldn't exist and 
dvander@1291
   208
		 * 2) people must be checking IsVoteInProgress() beforehand anyway.
dvander@1291
   209
		 */
dvander@1291
   210
		g_next_vote = gpGlobals->curtime + fVoteDelay + (float)max_time;
dvander@1291
   211
	}
dvander@1291
   212
dvander@2056
   213
	m_fStartTime = gpGlobals->curtime;
dvander@2056
   214
	m_nMenuTime = max_time;
dvander@2056
   215
dvander@1269
   216
	for (unsigned int i=0; i<num_clients; i++)
dvander@1269
   217
	{
dvander@2056
   218
		if (clients[i] < 1 || clients[i] > 256)
dvander@2056
   219
		{
dvander@2056
   220
			continue;
dvander@2056
   221
		}
dvander@1269
   222
		menu->Display(clients[i], max_time, this);
dvander@1269
   223
	}
dvander@1269
   224
dvander@1269
   225
	StartVoting();
dvander@1269
   226
dvander@1269
   227
	return true;
dvander@1269
   228
}
dvander@1269
   229
dvander@2056
   230
bool VoteMenuHandler::IsClientInVotePool(int client)
dvander@2056
   231
{
dvander@2056
   232
	if (client < 1 
dvander@2056
   233
		|| client > g_Players.MaxClients() 
dvander@2056
   234
		|| m_pCurMenu == NULL)
dvander@2056
   235
	{
dvander@2056
   236
		return false;
dvander@2056
   237
	}
dvander@2056
   238
pred@2801
   239
	return (m_ClientVotes[client] > VOTE_NOT_VOTING);
dvander@2056
   240
}
dvander@2056
   241
dvander@2056
   242
bool VoteMenuHandler::GetClientVoteChoice(int client, unsigned int *pItem)
dvander@2056
   243
{
dvander@2056
   244
	if (!IsClientInVotePool(client)
pred@2801
   245
		|| m_ClientVotes[client] == VOTE_PENDING)
dvander@2056
   246
	{
dvander@2056
   247
		return false;
dvander@2056
   248
	}
dvander@2056
   249
dvander@2056
   250
	*pItem = m_ClientVotes[client];
dvander@2056
   251
dvander@2056
   252
	return true;
dvander@2056
   253
}
dvander@2056
   254
dvander@2737
   255
bool VoteMenuHandler::RedrawToClient(int client, bool revotes)
dvander@2056
   256
{
dvander@2056
   257
	unsigned int time_limit;
dvander@2056
   258
dvander@2056
   259
	if (!IsClientInVotePool(client))
dvander@2056
   260
	{
dvander@2056
   261
		return false;
dvander@2056
   262
	}
dvander@2056
   263
dvander@2737
   264
	if (m_ClientVotes[client] >= 0)
dvander@2737
   265
	{
dvander@2737
   266
		if ((m_VoteFlags & VOTEFLAG_NO_REVOTES) == VOTEFLAG_NO_REVOTES || !revotes)
dvander@2737
   267
		{
dvander@2737
   268
			return false;
dvander@2737
   269
		}
dvander@2737
   270
		assert((unsigned)m_ClientVotes[client] < m_Items);
dvander@2737
   271
		assert(m_Votes[m_ClientVotes[client]] > 0);
dvander@2737
   272
		m_Votes[m_ClientVotes[client]]--;
pred@2801
   273
		m_ClientVotes[client] = VOTE_PENDING;
pred@2801
   274
		m_Revoting[client] = true;
pred@2801
   275
		m_NumVotes--;
dvander@2737
   276
	}
dvander@2737
   277
dvander@2056
   278
	if (m_nMenuTime == MENU_TIME_FOREVER)
dvander@2056
   279
	{
dvander@2056
   280
		time_limit = m_nMenuTime;
dvander@2056
   281
	}
dvander@2056
   282
	else
dvander@2056
   283
	{
dvander@2056
   284
		time_limit = (int)((float)m_nMenuTime - (gpGlobals->curtime - m_fStartTime));
dvander@2056
   285
		
dvander@2056
   286
		/* Make sure this doesn't round to zero */
dvander@2056
   287
		if (time_limit == MENU_TIME_FOREVER)
dvander@2056
   288
		{
dvander@2056
   289
			time_limit = 1;
dvander@2056
   290
		}
dvander@2056
   291
	}
dvander@2056
   292
dvander@2056
   293
	return m_pCurMenu->Display(client, time_limit, this);
dvander@2056
   294
}
dvander@2056
   295
dvander@1269
   296
bool VoteMenuHandler::InitializeVoting(IBaseMenu *menu, 
dvander@1269
   297
									   IMenuHandler *handler,
dvander@1269
   298
									   unsigned int time,
dvander@1269
   299
									   unsigned int flags)
dvander@1269
   300
{
dvander@1269
   301
	if (IsVoteInProgress())
dvander@1269
   302
	{
dvander@1269
   303
		return false;
dvander@1269
   304
	}
dvander@1269
   305
dvander@1269
   306
	InternalReset();
dvander@1269
   307
dvander@1269
   308
	/* Mark all clients as not voting */
dvander@1269
   309
	for (int i=1; i<=gpGlobals->maxClients; i++)
dvander@1269
   310
	{
pred@2801
   311
		m_ClientVotes[i] = VOTE_NOT_VOTING;
pred@2801
   312
		m_Revoting[i] = false;
dvander@1269
   313
	}
dvander@1269
   314
dvander@1269
   315
	m_Items = menu->GetItemCount();
dvander@1269
   316
dvander@1269
   317
	if (m_Votes.size() < (size_t)m_Items)
dvander@1269
   318
	{
dvander@1269
   319
		/* Only clear the items we need to... */
dvander@1269
   320
		size_t size = m_Votes.size();
dvander@1269
   321
		for (size_t i=0; i<size; i++)
dvander@1269
   322
		{
dvander@1269
   323
			m_Votes[i] = 0;
dvander@1269
   324
		}
dvander@1269
   325
		m_Votes.resize(m_Items, 0);
dvander@2056
   326
	}
dvander@2056
   327
	else
dvander@2056
   328
	{
dvander@1269
   329
		for (unsigned int i=0; i<m_Items; i++)
dvander@1269
   330
		{
dvander@1269
   331
			m_Votes[i] = 0;
dvander@1269
   332
		}
dvander@1269
   333
	}
dvander@1269
   334
dvander@1269
   335
	m_pCurMenu = menu;
dvander@1269
   336
	m_VoteTime = time;
dvander@1269
   337
	m_VoteFlags = flags;
dvander@1269
   338
	m_pHandler = handler;
dvander@1269
   339
dvander@1269
   340
	m_pHandler->OnMenuStart(m_pCurMenu);
dvander@1269
   341
dvander@1269
   342
	return true;
dvander@1269
   343
}
dvander@1269
   344
dvander@1269
   345
void VoteMenuHandler::StartVoting()
dvander@1269
   346
{
dvander@1269
   347
	if (!m_pCurMenu)
dvander@1269
   348
	{
dvander@1269
   349
		return;
dvander@1269
   350
	}
dvander@1269
   351
dvander@1269
   352
	m_bStarted = true;
dvander@1269
   353
dvander@1269
   354
	m_pHandler->OnMenuVoteStart(m_pCurMenu);
dvander@1269
   355
pred@2801
   356
	m_displayTimer = g_Timers.CreateTimer(this, 1.0, NULL, TIMER_FLAG_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
pred@2801
   357
dvander@1269
   358
	/* By now we know how many clients were set.  
dvander@1269
   359
	 * If there are none, we should end IMMEDIATELY.
dvander@1269
   360
	 */
dvander@1269
   361
	if (m_Clients == 0)
dvander@1269
   362
	{
dvander@1269
   363
		EndVoting();
dvander@1269
   364
	}
pred@2801
   365
pred@2801
   366
	m_TotalClients = m_Clients;
dvander@1269
   367
}
dvander@1269
   368
dvander@1269
   369
void VoteMenuHandler::DecrementPlayerCount()
dvander@1269
   370
{
dvander@1269
   371
	assert(m_Clients > 0);
dvander@1269
   372
dvander@1269
   373
	m_Clients--;
dvander@1269
   374
dvander@1269
   375
	if (m_bStarted && m_Clients == 0)
dvander@1269
   376
	{
dvander@1269
   377
		EndVoting();
dvander@1269
   378
	}
dvander@1269
   379
}
dvander@1269
   380
dvander@1269
   381
int SortVoteItems(const void *item1, const void *item2)
dvander@1269
   382
{
dvander@1269
   383
	return ((menu_vote_result_t::menu_item_vote_t *)item2)->count 
dvander@1269
   384
		- ((menu_vote_result_t::menu_item_vote_t *)item1)->count;
dvander@1269
   385
}
dvander@1269
   386
dvander@1269
   387
void VoteMenuHandler::EndVoting()
dvander@1269
   388
{
dvander@1291
   389
	/* Set when the next delay ends.  We ignore cancellation because a menu
dvander@1291
   390
	 * was, at one point, displayed, which is all that counts.  However, we
dvander@1291
   391
	 * do re-calculate the time just in case the menu had no time limit.
dvander@1291
   392
	 */
dvander@1291
   393
	float fVoteDelay = sm_vote_delay.GetFloat();
dvander@1291
   394
	if (fVoteDelay < 1.0)
dvander@1291
   395
	{
dvander@1291
   396
		g_next_vote = 0.0;
dvander@2056
   397
	}
dvander@2056
   398
	else
dvander@2056
   399
	{
dvander@1291
   400
		g_next_vote = gpGlobals->curtime + fVoteDelay;
dvander@1291
   401
	}
dvander@1291
   402
pred@2801
   403
	if (m_displayTimer)
pred@2801
   404
	{
pred@2801
   405
		g_Timers.KillTimer(m_displayTimer);
pred@2801
   406
	}
pred@2801
   407
dvander@1269
   408
	if (m_bCancelled)
dvander@1269
   409
	{
dvander@1269
   410
		/* If we were cancelled, don't bother tabulating anything.
dvander@1269
   411
		 * Reset just in case someone tries to redraw, which means
dvander@1269
   412
		 * we need to save our states.
dvander@1269
   413
		 */
dvander@1269
   414
		IBaseMenu *menu = m_pCurMenu;
dvander@1269
   415
		IMenuHandler *handler = m_pHandler;
dvander@1269
   416
		InternalReset();
dvander@1296
   417
		handler->OnMenuVoteCancel(menu, VoteCancel_Generic);
dvander@1269
   418
		handler->OnMenuEnd(menu, MenuEnd_VotingCancelled);
dvander@1269
   419
		return;
dvander@1269
   420
	}
dvander@1269
   421
dvander@1269
   422
	menu_vote_result_t vote;
dvander@1269
   423
	menu_vote_result_t::menu_client_vote_t client_vote[256];
dvander@1269
   424
	menu_vote_result_t::menu_item_vote_t item_vote[256];
dvander@1269
   425
dvander@1269
   426
	memset(&vote, 0, sizeof(vote));
dvander@1269
   427
dvander@1269
   428
	/* Build the item list */
dvander@1269
   429
	for (unsigned int i=0; i<m_Items; i++)
dvander@1269
   430
	{
dvander@1269
   431
		if (m_Votes[i] > 0)
dvander@1269
   432
		{
dvander@1269
   433
			item_vote[vote.num_items].count = m_Votes[i];
dvander@1269
   434
			item_vote[vote.num_items].item = i;
dvander@1269
   435
			vote.num_votes += m_Votes[i];
dvander@1269
   436
			vote.num_items++;
dvander@1269
   437
		}
dvander@1269
   438
	}
dvander@1269
   439
	vote.item_list = item_vote;
dvander@1269
   440
dvander@1269
   441
	if (!vote.num_votes)
dvander@1269
   442
	{
dvander@1269
   443
		IBaseMenu *menu = m_pCurMenu;
dvander@1269
   444
		IMenuHandler *handler = m_pHandler;
dvander@1269
   445
		InternalReset();
dvander@1296
   446
		handler->OnMenuVoteCancel(menu, VoteCancel_NoVotes);
dvander@1296
   447
		handler->OnMenuEnd(menu, MenuEnd_VotingCancelled);
dvander@1269
   448
		return;
dvander@1269
   449
	}
dvander@1269
   450
dvander@1269
   451
	/* Build the client list */
dvander@1269
   452
	for (int i=1; i<=gpGlobals->maxClients; i++)
dvander@1269
   453
	{
pred@2801
   454
		if (m_ClientVotes[i] >= VOTE_PENDING)
dvander@1269
   455
		{
dvander@1269
   456
			client_vote[vote.num_clients].client = i;
dvander@1269
   457
			client_vote[vote.num_clients].item = m_ClientVotes[i];
dvander@1269
   458
			vote.num_clients++;
dvander@1269
   459
		}
dvander@1269
   460
	}
dvander@1269
   461
	vote.client_list = client_vote;
dvander@1269
   462
dvander@1269
   463
	/* Sort the item list descending like we promised */
dvander@1269
   464
	qsort(item_vote,
dvander@1269
   465
		vote.num_items,
dvander@1269
   466
		sizeof(menu_vote_result_t::menu_item_vote_t),
dvander@1269
   467
		SortVoteItems);
dvander@1269
   468
dvander@1269
   469
	/* Save states, then clear what we've saved.
dvander@1269
   470
	 * This makes us re-entrant, which is always the safe way to go.
dvander@1269
   471
	 */
dvander@1269
   472
	IBaseMenu *menu = m_pCurMenu;
dvander@1269
   473
	IMenuHandler *handler = m_pHandler;
dvander@1269
   474
	InternalReset();
dvander@1269
   475
dvander@1269
   476
	/* Send vote info */
dvander@1269
   477
	handler->OnMenuVoteResults(menu, &vote);
dvander@1269
   478
	handler->OnMenuEnd(menu, MenuEnd_VotingDone);
dvander@1269
   479
}
dvander@1269
   480
dvander@1269
   481
void VoteMenuHandler::OnMenuStart(IBaseMenu *menu)
dvander@1269
   482
{
dvander@1269
   483
	m_Clients++;
dvander@1269
   484
}
dvander@1269
   485
dvander@1269
   486
void VoteMenuHandler::OnMenuEnd(IBaseMenu *menu, MenuEndReason reason)
dvander@1269
   487
{
dvander@1269
   488
	DecrementPlayerCount();
dvander@1269
   489
}
dvander@1269
   490
dvander@1269
   491
void VoteMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
dvander@1269
   492
{
dvander@1269
   493
	m_pHandler->OnMenuCancel(menu, client, reason);
dvander@1269
   494
}
dvander@1269
   495
dvander@1269
   496
void VoteMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display)
dvander@1269
   497
{
pred@2801
   498
	m_ClientVotes[client] = VOTE_PENDING;
dvander@1269
   499
	m_pHandler->OnMenuDisplay(menu, client, display);
dvander@1269
   500
}
dvander@1269
   501
dvander@1269
   502
unsigned int VoteMenuHandler::OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr)
dvander@1269
   503
{
dvander@1269
   504
	return m_pHandler->OnMenuDisplayItem(menu, client, panel, item, dr);
dvander@1269
   505
}
dvander@1269
   506
dvander@1269
   507
void VoteMenuHandler::OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style)
dvander@1269
   508
{
dvander@1269
   509
	m_pHandler->OnMenuDrawItem(menu, client, item, style);
dvander@1269
   510
}
dvander@1269
   511
dvander@1269
   512
void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
dvander@1269
   513
{
dvander@1269
   514
	/* Check by our item count, NOT the vote array size */
dvander@1269
   515
	if (item < m_Items)
dvander@1269
   516
	{
dvander@1269
   517
		m_ClientVotes[client] = item;
dvander@1269
   518
		m_Votes[item]++;
dvander@1269
   519
		m_NumVotes++;
pred@2801
   520
laftrykung@3504
   521
		if (sm_vote_chat.GetBool() || sm_vote_console.GetBool() || sm_vote_client_console.GetBool())
pred@2801
   522
		{
pred@2801
   523
			static char buffer[1024];
pred@2801
   524
			ItemDrawInfo dr;
pred@2801
   525
			menu->GetItemInfo(item, &dr);
pred@2801
   526
pred@2801
   527
			if (sm_vote_console.GetBool())
pred@2801
   528
			{
pred@2801
   529
				int target = SOURCEMOD_SERVER_LANGUAGE;
dvander@3004
   530
				logicore.CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Voted For",
dvander@3004
   531
				                       &target, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
pred@2801
   532
				Engine_LogPrintWrapper(buffer);
pred@2801
   533
			}
pred@2801
   534
			
pred@2801
   535
			if (sm_vote_chat.GetBool() || sm_vote_client_console.GetBool())
pred@2801
   536
			{
pred@2801
   537
				int maxclients = g_Players.GetMaxClients();
pred@2801
   538
				for (int i=1; i<=maxclients; i++)
pred@2801
   539
				{	
pred@2801
   540
					CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
pred@2801
   541
					assert(pPlayer);
pred@2801
   542
skamonkey@3160
   543
					if (pPlayer->IsInGame() && !pPlayer->IsFakeClient())
pred@2801
   544
					{
pred@2801
   545
						if (m_Revoting[client])
pred@2801
   546
						{
dvander@3004
   547
							logicore.CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Changed Vote",
dvander@3004
   548
							                       &i, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
pred@2801
   549
						}
pred@2801
   550
						else
pred@2801
   551
						{
dvander@3004
   552
							logicore.CoreTranslate(buffer, sizeof(buffer), "[SM] %T", 4, NULL, "Voted For",
dvander@3004
   553
							                       &i, g_Players.GetPlayerByIndex(client)->GetName(), dr.display);
pred@2801
   554
						}
pred@2801
   555
pred@2801
   556
						if (sm_vote_chat.GetBool())
pred@2801
   557
						{
pred@2801
   558
							g_HL2.TextMsg(i, HUD_PRINTTALK, buffer);
pred@2801
   559
						}
pred@2801
   560
pred@2801
   561
						if (sm_vote_client_console.GetBool())
pred@2801
   562
						{
laftrykung@3505
   563
							ClientConsolePrint(pPlayer->GetEdict(), buffer);
pred@2801
   564
						}		
pred@2801
   565
					}
pred@2801
   566
				}
pred@2801
   567
			}
pred@2801
   568
		}
pred@2801
   569
pred@2801
   570
		BuildVoteLeaders();
pred@2801
   571
		DrawHintProgress();
dvander@1269
   572
	}
dvander@1269
   573
dvander@1269
   574
	m_pHandler->OnMenuSelect(menu, client, item);
dvander@1269
   575
}
dvander@1269
   576
dvander@1474
   577
void VoteMenuHandler::OnMenuSelect2(IBaseMenu *menu, int client, unsigned int item, unsigned int item_on_page)
dvander@1474
   578
{
dvander@1474
   579
	if (m_pHandler->GetMenuAPIVersion2() >= 13)
dvander@1474
   580
	{
dvander@1474
   581
		m_pHandler->OnMenuSelect2(menu, client, item, item_on_page);
dvander@1474
   582
	}
dvander@1474
   583
}
dvander@1474
   584
dvander@1269
   585
void VoteMenuHandler::InternalReset()
dvander@1269
   586
{
dvander@1269
   587
	m_Clients = 0;
dvander@1269
   588
	m_Items = 0;
dvander@1269
   589
	m_bStarted = false;
dvander@1269
   590
	m_pCurMenu = NULL;
dvander@1269
   591
	m_NumVotes = 0;
dvander@1269
   592
	m_bCancelled = false;
dvander@1269
   593
	m_pHandler = NULL;
pred@2801
   594
	m_leaderList[0] = '\0';
pred@2801
   595
	m_displayTimer = NULL;
pred@2801
   596
	m_TotalClients = 0;
dvander@1269
   597
}
dvander@1269
   598
dvander@1269
   599
void VoteMenuHandler::CancelVoting()
dvander@1269
   600
{
dvander@1269
   601
	if (m_bCancelled || !m_pCurMenu)
dvander@1269
   602
	{
dvander@1269
   603
		return;
dvander@1269
   604
	}
dvander@1269
   605
	m_bCancelled = true;
dvander@1269
   606
	m_pCurMenu->Cancel();
dvander@1269
   607
}
dvander@1269
   608
dvander@1269
   609
IBaseMenu *VoteMenuHandler::GetCurrentMenu()
dvander@1269
   610
{
dvander@1269
   611
	return m_pCurMenu;
dvander@1269
   612
}
dvander@1269
   613
dvander@1269
   614
bool VoteMenuHandler::IsCancelling()
dvander@1269
   615
{
dvander@1269
   616
	return m_bCancelled;
dvander@1269
   617
}
dvander@2737
   618
pred@2801
   619
void VoteMenuHandler::DrawHintProgress()
pred@2801
   620
{
pred@2801
   621
	if (!sm_vote_hintbox.GetBool())
pred@2801
   622
	{
pred@2801
   623
		return;
pred@2801
   624
	}
pred@2801
   625
pred@2801
   626
	static char buffer[1024];
pred@2801
   627
pred@2801
   628
	float timeRemaining = (m_fStartTime + m_nMenuTime) - gpGlobals->curtime;
pred@2801
   629
	if (timeRemaining < 0)
pred@2801
   630
	{
pred@2801
   631
		timeRemaining = 0.0;
pred@2801
   632
	}
pred@2801
   633
pred@2801
   634
	int iTimeRemaining = RoundFloatToInt(timeRemaining);
pred@2801
   635
	
pred@2801
   636
	int maxclients = g_Players.GetMaxClients();
pred@2801
   637
	for (int i=1; i<=maxclients; i++)
pred@2801
   638
	{
pred@2801
   639
		if (g_Players.GetPlayerByIndex(i)->IsInGame())
pred@2801
   640
		{
dvander@3004
   641
			logicore.CoreTranslate(buffer, sizeof(buffer), "%T%s", 6, NULL, "Vote Count",
dvander@3004
   642
			                       &i, &m_NumVotes, &m_TotalClients, &iTimeRemaining, &m_leaderList);
pred@2801
   643
			g_HL2.HintTextMsg(i, buffer);
pred@2801
   644
		}
pred@2801
   645
	}
pred@2801
   646
}
pred@2801
   647
pred@2801
   648
void VoteMenuHandler::BuildVoteLeaders()
pred@2801
   649
{
pred@2801
   650
	if (m_NumVotes == 0 || !sm_vote_hintbox.GetBool())
pred@2801
   651
	{
pred@2801
   652
		return;
pred@2801
   653
	}
pred@2801
   654
pred@2801
   655
	menu_vote_result_t vote;
pred@2801
   656
	menu_vote_result_t::menu_item_vote_t item_vote[256];
pred@2801
   657
pred@2801
   658
	memset(&vote, 0, sizeof(vote));
pred@2801
   659
pred@2801
   660
	/* Build the item list */
pred@2801
   661
	for (unsigned int i=0; i<m_Items; i++)
pred@2801
   662
	{
pred@2801
   663
		if (m_Votes[i] > 0)
pred@2801
   664
		{
pred@2801
   665
			item_vote[vote.num_items].count = m_Votes[i];
pred@2801
   666
			item_vote[vote.num_items].item = i;
pred@2801
   667
			vote.num_votes += m_Votes[i];
pred@2801
   668
			vote.num_items++;
pred@2801
   669
		}
pred@2801
   670
	}
pred@2801
   671
	vote.item_list = item_vote;
pred@2801
   672
	assert(vote.num_votes);
pred@2801
   673
pred@2801
   674
	/* Sort the item list descending */
pred@2801
   675
	qsort(item_vote,
pred@2801
   676
		vote.num_items,
pred@2801
   677
		sizeof(menu_vote_result_t::menu_item_vote_t),
pred@2801
   678
		SortVoteItems);
pred@2801
   679
pred@2801
   680
	/* Take the top 3 (if applicable) and draw them */
pred@2801
   681
	int len = 0;
pred@2801
   682
	for (unsigned int i=0; i<vote.num_items && i<3; i++)
pred@2801
   683
	{
pred@2801
   684
		int curItem = vote.item_list[i].item;
pred@2801
   685
		ItemDrawInfo dr;
pred@2801
   686
		m_pCurMenu->GetItemInfo(curItem, &dr);
pred@2801
   687
		len += g_SourceMod.Format(m_leaderList + len, sizeof(m_leaderList) - len, "\n%i. %s: (%i)", i+1, dr.display, vote.item_list[i].count);
pred@2801
   688
	}
pred@2801
   689
}
pred@2801
   690
pred@2801
   691
SourceMod::ResultType VoteMenuHandler::OnTimer(ITimer *pTimer, void *pData)
pred@2801
   692
{
pred@2801
   693
	DrawHintProgress();
pred@2801
   694
pred@2801
   695
	return Pl_Continue;
pred@2801
   696
}
pred@2801
   697
pred@2801
   698
void VoteMenuHandler::OnTimerEnd(ITimer *pTimer, void *pData)
pred@2801
   699
{
pred@2801
   700
	m_displayTimer = NULL;
pred@2801
   701
}