1.1 --- a/core/MenuVoting.cpp Fri Jul 11 06:51:21 2008 +0000
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,491 +0,0 @@
1.4 -/**
1.5 - * vim: set ts=4 :
1.6 - * =============================================================================
1.7 - * SourceMod
1.8 - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 - * =============================================================================
1.10 - *
1.11 - * This program is free software; you can redistribute it and/or modify it under
1.12 - * the terms of the GNU General Public License, version 3.0, as published by the
1.13 - * Free Software Foundation.
1.14 - *
1.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 - * details.
1.19 - *
1.20 - * You should have received a copy of the GNU General Public License along with
1.21 - * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 - *
1.23 - * As a special exception, AlliedModders LLC gives you permission to link the
1.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 - * by the Valve Corporation. You must obey the GNU General Public License in
1.27 - * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 - * this exception to all derivative works. AlliedModders LLC defines further
1.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 - * or <http://www.sourcemod.net/license.php>.
1.31 - *
1.32 - * Version: $Id$
1.33 - */
1.34 -
1.35 -#include <string.h>
1.36 -#include <stdlib.h>
1.37 -#include "MenuVoting.h"
1.38 -#include "PlayerManager.h"
1.39 -#include "sourcemm_api.h"
1.40 -
1.41 -float g_next_vote = 0.0f;
1.42 -
1.43 -#if defined ORANGEBOX_BUILD
1.44 -void OnVoteDelayChange(IConVar *cvar, const char *value, float flOldValue);
1.45 -#else
1.46 -void OnVoteDelayChange(ConVar *cvar, const char *value);
1.47 -#endif
1.48 -ConVar sm_vote_delay("sm_vote_delay",
1.49 - "30",
1.50 - 0,
1.51 - "Sets the recommended time in between public votes",
1.52 - false,
1.53 - 0.0,
1.54 - false,
1.55 - 0.0,
1.56 - OnVoteDelayChange);
1.57 -
1.58 -#if defined ORANGEBOX_BUILD
1.59 -void OnVoteDelayChange(IConVar *cvar, const char *value, float flOldValue)
1.60 -#else
1.61 -void OnVoteDelayChange(ConVar *cvar, const char *value)
1.62 -#endif
1.63 -{
1.64 - /* See if the new vote delay isn't something we need to account for */
1.65 - if (sm_vote_delay.GetFloat() < 1.0f)
1.66 - {
1.67 - g_next_vote = 0.0f;
1.68 - return;
1.69 - }
1.70 -
1.71 - /* If there was never a last vote, ignore this change */
1.72 - if (g_next_vote < 0.1f)
1.73 - {
1.74 - return;
1.75 - }
1.76 -
1.77 - /* Subtract the original value, then add the new one. */
1.78 - g_next_vote -= (float)atof(value);
1.79 - g_next_vote += sm_vote_delay.GetFloat();
1.80 -}
1.81 -
1.82 -unsigned int VoteMenuHandler::GetRemainingVoteDelay()
1.83 -{
1.84 - if (g_next_vote <= gpGlobals->curtime)
1.85 - {
1.86 - return 0;
1.87 - }
1.88 -
1.89 - return (unsigned int)(g_next_vote - gpGlobals->curtime);
1.90 -}
1.91 -
1.92 -void VoteMenuHandler::OnSourceModAllInitialized()
1.93 -{
1.94 - g_Players.AddClientListener(this);
1.95 -}
1.96 -
1.97 -void VoteMenuHandler::OnSourceModShutdown()
1.98 -{
1.99 - g_Players.RemoveClientListener(this);
1.100 -}
1.101 -
1.102 -void VoteMenuHandler::OnSourceModLevelChange(const char *mapName)
1.103 -{
1.104 - g_next_vote = 0.0f;
1.105 -}
1.106 -
1.107 -unsigned int VoteMenuHandler::GetMenuAPIVersion2()
1.108 -{
1.109 - return m_pHandler->GetMenuAPIVersion2();
1.110 -}
1.111 -
1.112 -void VoteMenuHandler::OnClientDisconnected(int client)
1.113 -{
1.114 - if (!IsVoteInProgress())
1.115 - {
1.116 - return;
1.117 - }
1.118 -
1.119 - /* Wipe out their vote if they had one. We have to make sure the the the
1.120 - * newly connected client is not allowed to vote.
1.121 - */
1.122 - int item;
1.123 - if ((item = m_ClientVotes[client]) >= -1)
1.124 - {
1.125 - if (item >= 0)
1.126 - {
1.127 - assert((unsigned)item < m_Items);
1.128 - assert(m_Votes[item] > 0);
1.129 - m_Votes[item]--;
1.130 - }
1.131 - m_ClientVotes[client] = -2;
1.132 - }
1.133 -}
1.134 -
1.135 -bool VoteMenuHandler::IsVoteInProgress()
1.136 -{
1.137 - return (m_pCurMenu != NULL);
1.138 -}
1.139 -
1.140 -bool VoteMenuHandler::StartVote(IBaseMenu *menu,
1.141 - unsigned int num_clients,
1.142 - int clients[],
1.143 - unsigned int max_time,
1.144 - unsigned int flags/* =0 */)
1.145 -{
1.146 - if (!InitializeVoting(menu, menu->GetHandler(), max_time, flags))
1.147 - {
1.148 - return false;
1.149 - }
1.150 -
1.151 - /* Note: we can use game time and not universal time because
1.152 - * if we're voting then players are in-game.
1.153 - */
1.154 -
1.155 - float fVoteDelay = sm_vote_delay.GetFloat();
1.156 - if (fVoteDelay < 1.0)
1.157 - {
1.158 - g_next_vote = 0.0;
1.159 - }
1.160 - else
1.161 - {
1.162 - /* This little trick breaks for infinite votes!
1.163 - * However, we just ignore that since those 1) shouldn't exist and
1.164 - * 2) people must be checking IsVoteInProgress() beforehand anyway.
1.165 - */
1.166 - g_next_vote = gpGlobals->curtime + fVoteDelay + (float)max_time;
1.167 - }
1.168 -
1.169 - m_fStartTime = gpGlobals->curtime;
1.170 - m_nMenuTime = max_time;
1.171 -
1.172 - for (unsigned int i=0; i<num_clients; i++)
1.173 - {
1.174 - if (clients[i] < 1 || clients[i] > 256)
1.175 - {
1.176 - continue;
1.177 - }
1.178 - menu->Display(clients[i], max_time, this);
1.179 - }
1.180 -
1.181 - StartVoting();
1.182 -
1.183 - return true;
1.184 -}
1.185 -
1.186 -bool VoteMenuHandler::IsClientInVotePool(int client)
1.187 -{
1.188 - if (client < 1
1.189 - || client > g_Players.MaxClients()
1.190 - || m_pCurMenu == NULL)
1.191 - {
1.192 - return false;
1.193 - }
1.194 -
1.195 - return (m_ClientVotes[client] > -2);
1.196 -}
1.197 -
1.198 -bool VoteMenuHandler::GetClientVoteChoice(int client, unsigned int *pItem)
1.199 -{
1.200 - if (!IsClientInVotePool(client)
1.201 - || m_ClientVotes[client] == -1)
1.202 - {
1.203 - return false;
1.204 - }
1.205 -
1.206 - *pItem = m_ClientVotes[client];
1.207 -
1.208 - return true;
1.209 -}
1.210 -
1.211 -bool VoteMenuHandler::RedrawToClient(int client)
1.212 -{
1.213 - unsigned int time_limit;
1.214 -
1.215 - if (!IsClientInVotePool(client))
1.216 - {
1.217 - return false;
1.218 - }
1.219 -
1.220 - if (m_nMenuTime == MENU_TIME_FOREVER)
1.221 - {
1.222 - time_limit = m_nMenuTime;
1.223 - }
1.224 - else
1.225 - {
1.226 - time_limit = (int)((float)m_nMenuTime - (gpGlobals->curtime - m_fStartTime));
1.227 -
1.228 - /* Make sure this doesn't round to zero */
1.229 - if (time_limit == MENU_TIME_FOREVER)
1.230 - {
1.231 - time_limit = 1;
1.232 - }
1.233 - }
1.234 -
1.235 - return m_pCurMenu->Display(client, time_limit, this);
1.236 -}
1.237 -
1.238 -bool VoteMenuHandler::InitializeVoting(IBaseMenu *menu,
1.239 - IMenuHandler *handler,
1.240 - unsigned int time,
1.241 - unsigned int flags)
1.242 -{
1.243 - if (IsVoteInProgress())
1.244 - {
1.245 - return false;
1.246 - }
1.247 -
1.248 - InternalReset();
1.249 -
1.250 - /* Mark all clients as not voting */
1.251 - for (int i=1; i<=gpGlobals->maxClients; i++)
1.252 - {
1.253 - m_ClientVotes[i] = -2;
1.254 - }
1.255 -
1.256 - m_Items = menu->GetItemCount();
1.257 -
1.258 - if (m_Votes.size() < (size_t)m_Items)
1.259 - {
1.260 - /* Only clear the items we need to... */
1.261 - size_t size = m_Votes.size();
1.262 - for (size_t i=0; i<size; i++)
1.263 - {
1.264 - m_Votes[i] = 0;
1.265 - }
1.266 - m_Votes.resize(m_Items, 0);
1.267 - }
1.268 - else
1.269 - {
1.270 - for (unsigned int i=0; i<m_Items; i++)
1.271 - {
1.272 - m_Votes[i] = 0;
1.273 - }
1.274 - }
1.275 -
1.276 - m_pCurMenu = menu;
1.277 - m_VoteTime = time;
1.278 - m_VoteFlags = flags;
1.279 - m_pHandler = handler;
1.280 -
1.281 - m_pHandler->OnMenuStart(m_pCurMenu);
1.282 -
1.283 - return true;
1.284 -}
1.285 -
1.286 -void VoteMenuHandler::StartVoting()
1.287 -{
1.288 - if (!m_pCurMenu)
1.289 - {
1.290 - return;
1.291 - }
1.292 -
1.293 - m_bStarted = true;
1.294 -
1.295 - m_pHandler->OnMenuVoteStart(m_pCurMenu);
1.296 -
1.297 - /* By now we know how many clients were set.
1.298 - * If there are none, we should end IMMEDIATELY.
1.299 - */
1.300 - if (m_Clients == 0)
1.301 - {
1.302 - EndVoting();
1.303 - }
1.304 -}
1.305 -
1.306 -void VoteMenuHandler::DecrementPlayerCount()
1.307 -{
1.308 - assert(m_Clients > 0);
1.309 -
1.310 - m_Clients--;
1.311 -
1.312 - if (m_bStarted && m_Clients == 0)
1.313 - {
1.314 - EndVoting();
1.315 - }
1.316 -}
1.317 -
1.318 -int SortVoteItems(const void *item1, const void *item2)
1.319 -{
1.320 - return ((menu_vote_result_t::menu_item_vote_t *)item2)->count
1.321 - - ((menu_vote_result_t::menu_item_vote_t *)item1)->count;
1.322 -}
1.323 -
1.324 -void VoteMenuHandler::EndVoting()
1.325 -{
1.326 - /* Set when the next delay ends. We ignore cancellation because a menu
1.327 - * was, at one point, displayed, which is all that counts. However, we
1.328 - * do re-calculate the time just in case the menu had no time limit.
1.329 - */
1.330 - float fVoteDelay = sm_vote_delay.GetFloat();
1.331 - if (fVoteDelay < 1.0)
1.332 - {
1.333 - g_next_vote = 0.0;
1.334 - }
1.335 - else
1.336 - {
1.337 - g_next_vote = gpGlobals->curtime + fVoteDelay;
1.338 - }
1.339 -
1.340 - if (m_bCancelled)
1.341 - {
1.342 - /* If we were cancelled, don't bother tabulating anything.
1.343 - * Reset just in case someone tries to redraw, which means
1.344 - * we need to save our states.
1.345 - */
1.346 - IBaseMenu *menu = m_pCurMenu;
1.347 - IMenuHandler *handler = m_pHandler;
1.348 - InternalReset();
1.349 - handler->OnMenuVoteCancel(menu, VoteCancel_Generic);
1.350 - handler->OnMenuEnd(menu, MenuEnd_VotingCancelled);
1.351 - return;
1.352 - }
1.353 -
1.354 - menu_vote_result_t vote;
1.355 - menu_vote_result_t::menu_client_vote_t client_vote[256];
1.356 - menu_vote_result_t::menu_item_vote_t item_vote[256];
1.357 -
1.358 - memset(&vote, 0, sizeof(vote));
1.359 -
1.360 - /* Build the item list */
1.361 - for (unsigned int i=0; i<m_Items; i++)
1.362 - {
1.363 - if (m_Votes[i] > 0)
1.364 - {
1.365 - item_vote[vote.num_items].count = m_Votes[i];
1.366 - item_vote[vote.num_items].item = i;
1.367 - vote.num_votes += m_Votes[i];
1.368 - vote.num_items++;
1.369 - }
1.370 - }
1.371 - vote.item_list = item_vote;
1.372 -
1.373 - if (!vote.num_votes)
1.374 - {
1.375 - IBaseMenu *menu = m_pCurMenu;
1.376 - IMenuHandler *handler = m_pHandler;
1.377 - InternalReset();
1.378 - handler->OnMenuVoteCancel(menu, VoteCancel_NoVotes);
1.379 - handler->OnMenuEnd(menu, MenuEnd_VotingCancelled);
1.380 - return;
1.381 - }
1.382 -
1.383 - /* Build the client list */
1.384 - for (int i=1; i<=gpGlobals->maxClients; i++)
1.385 - {
1.386 - if (m_ClientVotes[i] >= -1)
1.387 - {
1.388 - client_vote[vote.num_clients].client = i;
1.389 - client_vote[vote.num_clients].item = m_ClientVotes[i];
1.390 - vote.num_clients++;
1.391 - }
1.392 - }
1.393 - vote.client_list = client_vote;
1.394 -
1.395 - /* Sort the item list descending like we promised */
1.396 - qsort(item_vote,
1.397 - vote.num_items,
1.398 - sizeof(menu_vote_result_t::menu_item_vote_t),
1.399 - SortVoteItems);
1.400 -
1.401 - /* Save states, then clear what we've saved.
1.402 - * This makes us re-entrant, which is always the safe way to go.
1.403 - */
1.404 - IBaseMenu *menu = m_pCurMenu;
1.405 - IMenuHandler *handler = m_pHandler;
1.406 - InternalReset();
1.407 -
1.408 - /* Send vote info */
1.409 - handler->OnMenuVoteResults(menu, &vote);
1.410 - handler->OnMenuEnd(menu, MenuEnd_VotingDone);
1.411 -}
1.412 -
1.413 -void VoteMenuHandler::OnMenuStart(IBaseMenu *menu)
1.414 -{
1.415 - m_Clients++;
1.416 -}
1.417 -
1.418 -void VoteMenuHandler::OnMenuEnd(IBaseMenu *menu, MenuEndReason reason)
1.419 -{
1.420 - DecrementPlayerCount();
1.421 -}
1.422 -
1.423 -void VoteMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
1.424 -{
1.425 - m_pHandler->OnMenuCancel(menu, client, reason);
1.426 -}
1.427 -
1.428 -void VoteMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display)
1.429 -{
1.430 - m_ClientVotes[client] = -1;
1.431 - m_pHandler->OnMenuDisplay(menu, client, display);
1.432 -}
1.433 -
1.434 -unsigned int VoteMenuHandler::OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr)
1.435 -{
1.436 - return m_pHandler->OnMenuDisplayItem(menu, client, panel, item, dr);
1.437 -}
1.438 -
1.439 -void VoteMenuHandler::OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style)
1.440 -{
1.441 - m_pHandler->OnMenuDrawItem(menu, client, item, style);
1.442 -}
1.443 -
1.444 -void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
1.445 -{
1.446 - /* Check by our item count, NOT the vote array size */
1.447 - if (item < m_Items)
1.448 - {
1.449 - m_ClientVotes[client] = item;
1.450 - m_Votes[item]++;
1.451 - m_NumVotes++;
1.452 - }
1.453 -
1.454 - m_pHandler->OnMenuSelect(menu, client, item);
1.455 -}
1.456 -
1.457 -void VoteMenuHandler::OnMenuSelect2(IBaseMenu *menu, int client, unsigned int item, unsigned int item_on_page)
1.458 -{
1.459 - if (m_pHandler->GetMenuAPIVersion2() >= 13)
1.460 - {
1.461 - m_pHandler->OnMenuSelect2(menu, client, item, item_on_page);
1.462 - }
1.463 -}
1.464 -
1.465 -void VoteMenuHandler::InternalReset()
1.466 -{
1.467 - m_Clients = 0;
1.468 - m_Items = 0;
1.469 - m_bStarted = false;
1.470 - m_pCurMenu = NULL;
1.471 - m_NumVotes = 0;
1.472 - m_bCancelled = false;
1.473 - m_pHandler = NULL;
1.474 -}
1.475 -
1.476 -void VoteMenuHandler::CancelVoting()
1.477 -{
1.478 - if (m_bCancelled || !m_pCurMenu)
1.479 - {
1.480 - return;
1.481 - }
1.482 - m_bCancelled = true;
1.483 - m_pCurMenu->Cancel();
1.484 -}
1.485 -
1.486 -IBaseMenu *VoteMenuHandler::GetCurrentMenu()
1.487 -{
1.488 - return m_pCurMenu;
1.489 -}
1.490 -
1.491 -bool VoteMenuHandler::IsCancelling()
1.492 -{
1.493 - return m_bCancelled;
1.494 -}