1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/MenuVoting.cpp Wed Aug 08 02:27:10 2007 +0000
1.3 @@ -0,0 +1,326 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * ================================================================
1.7 + * SourceMod
1.8 + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
1.9 + * ================================================================
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or
1.12 + * modify it under the terms of the GNU General Public License,
1.13 + * version 3.0, as published by the Free Software Foundation.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful,
1.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.18 + * GNU General Public License for more details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License
1.21 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
1.22 + *
1.23 + * As a special exception, AlliedModders LLC gives you permission to
1.24 + * link the code of this program (as well as its derivative works) to
1.25 + * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any
1.26 + * Game MODs that run on software by the Valve Corporation. You must
1.27 + * obey the GNU General Public License in all respects for all other
1.28 + * code used. Additionally, AlliedModders LLC grants this exception
1.29 + * to all derivative works. AlliedModders LLC defines further
1.30 + * exceptions, found in LICENSE.txt (as of this writing, version
1.31 + * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
1.32 + *
1.33 + * Version: $Id$
1.34 + */
1.35 +
1.36 +#include <string.h>
1.37 +#include <stdlib.h>
1.38 +#include "MenuVoting.h"
1.39 +#include "PlayerManager.h"
1.40 +#include "sourcemm_api.h"
1.41 +
1.42 +void VoteMenuHandler::OnSourceModAllInitialized()
1.43 +{
1.44 + g_Players.AddClientListener(this);
1.45 +}
1.46 +
1.47 +void VoteMenuHandler::OnSourceModShutdown()
1.48 +{
1.49 + g_Players.RemoveClientListener(this);
1.50 +}
1.51 +
1.52 +unsigned int VoteMenuHandler::GetMenuAPIVersion2()
1.53 +{
1.54 + return m_pHandler->GetMenuAPIVersion2();
1.55 +}
1.56 +
1.57 +void VoteMenuHandler::OnClientDisconnected(int client)
1.58 +{
1.59 + if (!IsVoteInProgress())
1.60 + {
1.61 + return;
1.62 + }
1.63 +
1.64 + /* Wipe out their vote if they had one */
1.65 + int item;
1.66 + if ((item = m_ClientVotes[client]) >= 0)
1.67 + {
1.68 + assert((unsigned)item < m_Items);
1.69 + assert(m_Votes[item] > 0);
1.70 + m_Votes[item]--;
1.71 + m_ClientVotes[client] = -1;
1.72 + }
1.73 +}
1.74 +
1.75 +bool VoteMenuHandler::IsVoteInProgress()
1.76 +{
1.77 + return (m_pCurMenu != NULL);
1.78 +}
1.79 +
1.80 +bool VoteMenuHandler::StartVote(IBaseMenu *menu, unsigned int num_clients, int clients[], unsigned int max_time, unsigned int flags/* =0 */)
1.81 +{
1.82 + if (!InitializeVoting(menu, menu->GetHandler(), max_time, flags))
1.83 + {
1.84 + return false;
1.85 + }
1.86 +
1.87 + for (unsigned int i=0; i<num_clients; i++)
1.88 + {
1.89 + menu->Display(clients[i], max_time, this);
1.90 + }
1.91 +
1.92 + StartVoting();
1.93 +
1.94 + return true;
1.95 +}
1.96 +
1.97 +bool VoteMenuHandler::InitializeVoting(IBaseMenu *menu,
1.98 + IMenuHandler *handler,
1.99 + unsigned int time,
1.100 + unsigned int flags)
1.101 +{
1.102 + if (IsVoteInProgress())
1.103 + {
1.104 + return false;
1.105 + }
1.106 +
1.107 + InternalReset();
1.108 +
1.109 + /* Mark all clients as not voting */
1.110 + for (int i=1; i<=gpGlobals->maxClients; i++)
1.111 + {
1.112 + m_ClientVotes[i] = -2;
1.113 + }
1.114 +
1.115 + m_Items = menu->GetItemCount();
1.116 +
1.117 + if (m_Votes.size() < (size_t)m_Items)
1.118 + {
1.119 + /* Only clear the items we need to... */
1.120 + size_t size = m_Votes.size();
1.121 + for (size_t i=0; i<size; i++)
1.122 + {
1.123 + m_Votes[i] = 0;
1.124 + }
1.125 + m_Votes.resize(m_Items, 0);
1.126 + } else {
1.127 + for (unsigned int i=0; i<m_Items; i++)
1.128 + {
1.129 + m_Votes[i] = 0;
1.130 + }
1.131 + }
1.132 +
1.133 + m_pCurMenu = menu;
1.134 + m_VoteTime = time;
1.135 + m_VoteFlags = flags;
1.136 + m_pHandler = handler;
1.137 +
1.138 + m_pHandler->OnMenuStart(m_pCurMenu);
1.139 +
1.140 + return true;
1.141 +}
1.142 +
1.143 +void VoteMenuHandler::StartVoting()
1.144 +{
1.145 + if (!m_pCurMenu)
1.146 + {
1.147 + return;
1.148 + }
1.149 +
1.150 + m_bStarted = true;
1.151 +
1.152 + m_pHandler->OnMenuVoteStart(m_pCurMenu);
1.153 +
1.154 + /* By now we know how many clients were set.
1.155 + * If there are none, we should end IMMEDIATELY.
1.156 + */
1.157 + if (m_Clients == 0)
1.158 + {
1.159 + EndVoting();
1.160 + }
1.161 +}
1.162 +
1.163 +void VoteMenuHandler::DecrementPlayerCount()
1.164 +{
1.165 + assert(m_Clients > 0);
1.166 +
1.167 + m_Clients--;
1.168 +
1.169 + if (m_bStarted && m_Clients == 0)
1.170 + {
1.171 + EndVoting();
1.172 + }
1.173 +}
1.174 +
1.175 +int SortVoteItems(const void *item1, const void *item2)
1.176 +{
1.177 + return ((menu_vote_result_t::menu_item_vote_t *)item2)->count
1.178 + - ((menu_vote_result_t::menu_item_vote_t *)item1)->count;
1.179 +}
1.180 +
1.181 +void VoteMenuHandler::EndVoting()
1.182 +{
1.183 + if (m_bCancelled)
1.184 + {
1.185 + /* If we were cancelled, don't bother tabulating anything.
1.186 + * Reset just in case someone tries to redraw, which means
1.187 + * we need to save our states.
1.188 + */
1.189 + IBaseMenu *menu = m_pCurMenu;
1.190 + IMenuHandler *handler = m_pHandler;
1.191 + InternalReset();
1.192 + handler->OnMenuVoteCancel(menu);
1.193 + handler->OnMenuEnd(menu, MenuEnd_VotingCancelled);
1.194 + return;
1.195 + }
1.196 +
1.197 + menu_vote_result_t vote;
1.198 + menu_vote_result_t::menu_client_vote_t client_vote[256];
1.199 + menu_vote_result_t::menu_item_vote_t item_vote[256];
1.200 +
1.201 + memset(&vote, 0, sizeof(vote));
1.202 +
1.203 + /* Build the item list */
1.204 + for (unsigned int i=0; i<m_Items; i++)
1.205 + {
1.206 + if (m_Votes[i] > 0)
1.207 + {
1.208 + item_vote[vote.num_items].count = m_Votes[i];
1.209 + item_vote[vote.num_items].item = i;
1.210 + vote.num_votes += m_Votes[i];
1.211 + vote.num_items++;
1.212 + }
1.213 + }
1.214 + vote.item_list = item_vote;
1.215 +
1.216 + if (!vote.num_votes)
1.217 + {
1.218 + IBaseMenu *menu = m_pCurMenu;
1.219 + IMenuHandler *handler = m_pHandler;
1.220 + InternalReset();
1.221 + handler->OnMenuVoteCancel(menu);
1.222 + handler->OnMenuEnd(menu, MenuEnd_NoVotes);
1.223 + return;
1.224 + }
1.225 +
1.226 + /* Build the client list */
1.227 + for (int i=1; i<=gpGlobals->maxClients; i++)
1.228 + {
1.229 + if (m_ClientVotes[i] >= -1)
1.230 + {
1.231 + client_vote[vote.num_clients].client = i;
1.232 + client_vote[vote.num_clients].item = m_ClientVotes[i];
1.233 + vote.num_clients++;
1.234 + }
1.235 + }
1.236 + vote.client_list = client_vote;
1.237 +
1.238 + /* Sort the item list descending like we promised */
1.239 + qsort(item_vote,
1.240 + vote.num_items,
1.241 + sizeof(menu_vote_result_t::menu_item_vote_t),
1.242 + SortVoteItems);
1.243 +
1.244 + /* Save states, then clear what we've saved.
1.245 + * This makes us re-entrant, which is always the safe way to go.
1.246 + */
1.247 + IBaseMenu *menu = m_pCurMenu;
1.248 + IMenuHandler *handler = m_pHandler;
1.249 + InternalReset();
1.250 +
1.251 + /* Send vote info */
1.252 + handler->OnMenuVoteResults(menu, &vote);
1.253 + handler->OnMenuEnd(menu, MenuEnd_VotingDone);
1.254 +}
1.255 +
1.256 +void VoteMenuHandler::OnMenuStart(IBaseMenu *menu)
1.257 +{
1.258 + m_Clients++;
1.259 +}
1.260 +
1.261 +void VoteMenuHandler::OnMenuEnd(IBaseMenu *menu, MenuEndReason reason)
1.262 +{
1.263 + DecrementPlayerCount();
1.264 +}
1.265 +
1.266 +void VoteMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
1.267 +{
1.268 + m_pHandler->OnMenuCancel(menu, client, reason);
1.269 +}
1.270 +
1.271 +void VoteMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display)
1.272 +{
1.273 + m_ClientVotes[client] = -1;
1.274 + m_pHandler->OnMenuDisplay(menu, client, display);
1.275 +}
1.276 +
1.277 +unsigned int VoteMenuHandler::OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr)
1.278 +{
1.279 + return m_pHandler->OnMenuDisplayItem(menu, client, panel, item, dr);
1.280 +}
1.281 +
1.282 +void VoteMenuHandler::OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style)
1.283 +{
1.284 + m_pHandler->OnMenuDrawItem(menu, client, item, style);
1.285 +}
1.286 +
1.287 +void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
1.288 +{
1.289 + /* Check by our item count, NOT the vote array size */
1.290 + if (item < m_Items)
1.291 + {
1.292 + m_ClientVotes[client] = item;
1.293 + m_Votes[item]++;
1.294 + m_NumVotes++;
1.295 + }
1.296 +
1.297 + m_pHandler->OnMenuSelect(menu, client, item);
1.298 +}
1.299 +
1.300 +void VoteMenuHandler::InternalReset()
1.301 +{
1.302 + m_Clients = 0;
1.303 + m_Items = 0;
1.304 + m_bStarted = false;
1.305 + m_pCurMenu = NULL;
1.306 + m_NumVotes = 0;
1.307 + m_bCancelled = false;
1.308 + m_pHandler = NULL;
1.309 +}
1.310 +
1.311 +void VoteMenuHandler::CancelVoting()
1.312 +{
1.313 + if (m_bCancelled || !m_pCurMenu)
1.314 + {
1.315 + return;
1.316 + }
1.317 + m_bCancelled = true;
1.318 + m_pCurMenu->Cancel();
1.319 +}
1.320 +
1.321 +IBaseMenu *VoteMenuHandler::GetCurrentMenu()
1.322 +{
1.323 + return m_pCurMenu;
1.324 +}
1.325 +
1.326 +bool VoteMenuHandler::IsCancelling()
1.327 +{
1.328 + return m_bCancelled;
1.329 +}