added experimental voting API
authorDavid Anderson <dvander@alliedmods.net>
Tue Jun 05 16:27:45 2007 +0000 (2007-06-05)
changeset 877898c39fbfde9
parent 876 a6095922d169
child 878 967a6613eb7e
added experimental voting API
core/MenuManager.cpp
core/MenuManager.h
core/MenuStyle_Base.cpp
core/MenuStyle_Base.h
core/MenuStyle_Radio.cpp
core/MenuStyle_Radio.h
core/MenuStyle_Valve.cpp
core/MenuStyle_Valve.h
public/IMenuManager.h
     1.1 --- a/core/MenuManager.cpp	Tue Jun 05 05:45:48 2007 +0000
     1.2 +++ b/core/MenuManager.cpp	Tue Jun 05 16:27:45 2007 +0000
     1.3 @@ -12,9 +12,9 @@
     1.4   * Version: $Id$
     1.5   */
     1.6  
     1.7 -
     1.8 +#include <time.h>
     1.9  #include <stdarg.h>
    1.10 -#include <time.h>
    1.11 +#include <stdlib.h>
    1.12  #include "MenuManager.h"
    1.13  #include "sm_stringutil.h"
    1.14  #include "sourcemm_api.h"
    1.15 @@ -25,115 +25,188 @@
    1.16  
    1.17  MenuManager g_Menus;
    1.18  
    1.19 -/*************************************
    1.20 - *************************************
    1.21 - **** BROADCAST HANDLING WRAPPERS ****
    1.22 - *************************************
    1.23 - *************************************/
    1.24 +/*******************************
    1.25 + *******************************
    1.26 + ******** VOTE HANDLER *********
    1.27 + *******************************
    1.28 + *******************************/
    1.29  
    1.30 -BroadcastHandler::BroadcastHandler(IMenuHandler *handler) : m_pHandler(handler), numClients(0)
    1.31 -{
    1.32 -}
    1.33 -
    1.34 -unsigned int BroadcastHandler::GetMenuAPIVersion2()
    1.35 +unsigned int VoteMenuHandler::GetMenuAPIVersion2()
    1.36  {
    1.37  	return m_pHandler->GetMenuAPIVersion2();
    1.38  }
    1.39  
    1.40 -void BroadcastHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
    1.41 +bool VoteMenuHandler::IsVoteInProgress()
    1.42 +{
    1.43 +	return (m_pCurMenu != NULL);
    1.44 +}
    1.45 +
    1.46 +void VoteMenuHandler::InitializeVoting(IBaseMenu *menu)
    1.47 +{
    1.48 +	m_Items = menu->GetItemCount();
    1.49 +
    1.50 +	if (m_Votes.size() < (size_t)m_Items)
    1.51 +	{
    1.52 +		/* Only clear the items we need to... */
    1.53 +		size_t size = m_Votes.size();
    1.54 +		for (size_t i=0; i<size; i++)
    1.55 +		{
    1.56 +			m_Votes[i] = 0;
    1.57 +		}
    1.58 +		m_Votes.resize(m_Items, 0);
    1.59 +	} else {
    1.60 +		for (unsigned int i=0; i<m_Items; i++)
    1.61 +		{
    1.62 +			m_Votes[i] = 0;
    1.63 +		}
    1.64 +	}
    1.65 +
    1.66 +	m_pCurMenu = menu;
    1.67 +
    1.68 +	m_pHandler->OnMenuStart(m_pCurMenu);
    1.69 +}
    1.70 +
    1.71 +void VoteMenuHandler::StartVoting()
    1.72 +{
    1.73 +	m_bStarted = true;
    1.74 +
    1.75 +	m_pHandler->OnMenuVoteStart(m_pCurMenu);
    1.76 +
    1.77 +	/* By now we know how many clients were set.  
    1.78 +	 * If there are none, we should end IMMEDIATELY.
    1.79 +	 */
    1.80 +	if (m_Clients == 0)
    1.81 +	{
    1.82 +		EndVoting();
    1.83 +	}
    1.84 +}
    1.85 +
    1.86 +void VoteMenuHandler::DecrementPlayerCount()
    1.87 +{
    1.88 +	assert(m_Clients > 0);
    1.89 +
    1.90 +	m_Clients--;
    1.91 +
    1.92 +	if (m_bStarted && m_Clients == 0)
    1.93 +	{
    1.94 +		EndVoting();
    1.95 +	}
    1.96 +}
    1.97 +
    1.98 +void VoteMenuHandler::EndVoting()
    1.99 +{
   1.100 +	unsigned int chosen = 0;
   1.101 +
   1.102 +	/* If we got zero votes, take a shortcut. */
   1.103 +	if (m_NumVotes == 0)
   1.104 +	{
   1.105 +		/* Pick a random item and then jump far, far away. */
   1.106 +		srand((unsigned int)(time(NULL)));
   1.107 +		chosen = (unsigned int)rand() % static_cast<unsigned int>(m_Votes.size());
   1.108 +		goto picked_item;
   1.109 +	}
   1.110 +
   1.111 +	/* We can't have more dups than this!
   1.112 +	 * This is the max number of players.
   1.113 +	 */
   1.114 +	unsigned int dup_array[256];
   1.115 +	unsigned int dup_count = 0;
   1.116 +
   1.117 +	size_t highest = 0;
   1.118 +	for (size_t i=1; i<m_Votes.size(); i++)
   1.119 +	{
   1.120 +		if (m_Votes[i] > m_Votes[highest])
   1.121 +		{
   1.122 +			/* If we have a new highest count, mark it and trash the duplicate
   1.123 +			 * list by setting the total to 0.
   1.124 +			 */
   1.125 +			highest = i;
   1.126 +			dup_count = 0;
   1.127 +		} else if (m_Votes[i] == m_Votes[highest]) {
   1.128 +			/* If they're equal, mark it in the duplicate list.
   1.129 +			 * We'll add in the original later.
   1.130 +			 */
   1.131 +			dup_array[dup_count++] = i;
   1.132 +		}
   1.133 +	}
   1.134 +
   1.135 +	/* Check if we need to pick from the duplicate list */
   1.136 +	if (dup_count)
   1.137 +	{
   1.138 +		/* Re-add the original to the list because it's not in there. */
   1.139 +		dup_array[dup_count++] = (unsigned int)highest;
   1.140 +
   1.141 +		/* Pick a random slot. */
   1.142 +		srand((unsigned int)(time(NULL)));
   1.143 +		unsigned int r = (unsigned int)rand() % dup_count;
   1.144 +
   1.145 +		/* Pick the item. */
   1.146 +		chosen = dup_array[r];
   1.147 +	} else {
   1.148 +		chosen = (unsigned int)highest;
   1.149 +	}
   1.150 +
   1.151 +picked_item:
   1.152 +	m_pHandler->OnMenuVoteEnd(m_pCurMenu, chosen);
   1.153 +	m_pHandler->OnMenuEnd(m_pCurMenu);
   1.154 +	InternalReset();
   1.155 +}
   1.156 +
   1.157 +void VoteMenuHandler::OnMenuStart(IBaseMenu *menu)
   1.158 +{
   1.159 +	m_Clients++;
   1.160 +}
   1.161 +
   1.162 +void VoteMenuHandler::OnMenuEnd(IBaseMenu *menu)
   1.163 +{
   1.164 +	DecrementPlayerCount();
   1.165 +}
   1.166 +
   1.167 +void VoteMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
   1.168  {
   1.169  	m_pHandler->OnMenuCancel(menu, client, reason);
   1.170  }
   1.171  
   1.172 -void BroadcastHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display)
   1.173 +void VoteMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display)
   1.174  {
   1.175 -	numClients++;
   1.176  	m_pHandler->OnMenuDisplay(menu, client, display);
   1.177  }
   1.178  
   1.179 -void BroadcastHandler::OnBroadcastEnd(IBaseMenu *menu)
   1.180 +void VoteMenuHandler::OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display)
   1.181  {
   1.182 -	g_Menus.FreeBroadcastHandler(this);
   1.183 +	m_pHandler->OnMenuDisplayItem(menu, client, item, display);
   1.184 +}
   1.185 +
   1.186 +void VoteMenuHandler::OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style)
   1.187 +{
   1.188 +	m_pHandler->OnMenuDrawItem(menu, client, item, style);
   1.189  }
   1.190  
   1.191 -void BroadcastHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
   1.192 +void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
   1.193  {
   1.194 +	/* Check by our item count, NOT the vote array size */
   1.195 +	if (item < m_Items)
   1.196 +	{
   1.197 +		m_Votes[item]++;
   1.198 +		m_NumVotes++;
   1.199 +	}
   1.200 +
   1.201  	m_pHandler->OnMenuSelect(menu, client, item);
   1.202  }
   1.203  
   1.204 -void BroadcastHandler::OnMenuEnd(IBaseMenu *menu)
   1.205 -{
   1.206 -	assert(numClients > 0);
   1.207 -
   1.208 -	/* Only fire if all clients have gotten a menu end */
   1.209 -	if (--numClients == 0)
   1.210 -	{
   1.211 -		IMenuHandler *pHandler = m_pHandler;
   1.212 -		OnBroadcastEnd(menu);
   1.213 -		pHandler->OnMenuEnd(menu);
   1.214 -	}
   1.215 -}
   1.216 -
   1.217 -VoteHandler::VoteHandler(IMenuVoteHandler *handler) 
   1.218 -: BroadcastHandler(handler), m_pVoteHandler(handler)
   1.219 +void VoteMenuHandler::Reset(IMenuHandler *mh)
   1.220  {
   1.221 -}
   1.222 -
   1.223 -void VoteHandler::Initialize(IBaseMenu *menu)
   1.224 -{
   1.225 -	unsigned int numItems = menu->GetItemCount();
   1.226 -
   1.227 -	if (m_counts.size() >= numItems)
   1.228 -	{
   1.229 -		for (size_t i=0; i<numItems; i++)
   1.230 -		{
   1.231 -			m_counts[i] = 0;
   1.232 -		}
   1.233 -	} else {
   1.234 -		for (size_t i=0; i<m_counts.size(); i++)
   1.235 -		{
   1.236 -			m_counts[i] = 0;
   1.237 -		}
   1.238 -		m_counts.resize(numItems, 0);
   1.239 -	}
   1.240 +	m_pHandler = mh;
   1.241 +	InternalReset();
   1.242  }
   1.243  
   1.244 -void VoteHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
   1.245 -{
   1.246 -	if (item < numItems)
   1.247 -	{
   1.248 -		m_counts[item]++;
   1.249 -	}
   1.250 -
   1.251 -	BroadcastHandler::OnMenuSelect(menu, client, item);
   1.252 -}
   1.253 -
   1.254 -void VoteHandler::OnBroadcastEnd(IBaseMenu *menu)
   1.255 +void VoteMenuHandler::InternalReset()
   1.256  {
   1.257 -	m_ties.clear();
   1.258 -
   1.259 -	size_t highest = 0;
   1.260 -	for (size_t i=1; i<numItems; i++)
   1.261 -	{
   1.262 -		if (m_counts[i] > m_counts[highest])
   1.263 -		{
   1.264 -			m_ties.clear();
   1.265 -			highest = i;
   1.266 -		} else if (m_counts[i] == m_counts[highest]) {
   1.267 -			m_ties.push_back(i);
   1.268 -		}
   1.269 -	}
   1.270 -
   1.271 -	if (m_ties.size())
   1.272 -	{
   1.273 -		m_ties.push_back(highest);
   1.274 -		srand(static_cast<unsigned int>(time(NULL)));
   1.275 -		highest = m_ties[rand() % m_ties.size()];
   1.276 -	}
   1.277 -
   1.278 -	m_pVoteHandler->OnMenuVoteEnd(menu, highest);
   1.279 -
   1.280 -	g_Menus.FreeVoteHandler(this);
   1.281 +	m_Clients = 0;
   1.282 +	m_Items = 0;
   1.283 +	m_bStarted = false;
   1.284 +	m_pCurMenu = NULL;
   1.285 +	m_NumVotes = 0;
   1.286  }
   1.287  
   1.288  /*******************************
   1.289 @@ -169,12 +242,6 @@
   1.290  	g_HandleSys.RemoveType(m_MenuType, g_pCoreIdent);
   1.291  	g_HandleSys.RemoveType(m_StyleType, g_pCoreIdent);
   1.292  
   1.293 -	while (!m_BroadcastHandlers.empty())
   1.294 -	{
   1.295 -		delete m_BroadcastHandlers.front();
   1.296 -		m_BroadcastHandlers.pop();
   1.297 -	}
   1.298 -
   1.299  	while (!m_VoteHandlers.empty())
   1.300  	{
   1.301  		delete m_VoteHandlers.front();
   1.302 @@ -659,119 +726,34 @@
   1.303  	return display;
   1.304  }
   1.305  
   1.306 -#if 0
   1.307 -unsigned int MenuManager::BroadcastMenu(IBaseMenu *menu, 
   1.308 -										IMenuHandler *handler, 
   1.309 -										int clients[], 
   1.310 -										unsigned int numClients, 
   1.311 -										unsigned int time)
   1.312 -{
   1.313 -	BroadcastHandler *bh;
   1.314 -
   1.315 -	if (m_BroadcastHandlers.empty())
   1.316 -	{
   1.317 -		bh = new BroadcastHandler(handler);
   1.318 -	} else {
   1.319 -		bh = m_BroadcastHandlers.front();
   1.320 -		m_BroadcastHandlers.pop();
   1.321 -		bh->m_pHandler = handler;
   1.322 -		bh->numClients = 0;
   1.323 -	}
   1.324 -
   1.325 -	handler->OnMenuStart(menu);
   1.326 -
   1.327 -	unsigned int total = 0;
   1.328 -	for (unsigned int i=0; i<numClients; i++)
   1.329 -	{
   1.330 -		/* Only continue if displaying works */
   1.331 -		if (!menu->Display(clients[i], bh, time))
   1.332 -		{
   1.333 -			continue;
   1.334 -		}
   1.335 -
   1.336 -		/* :TODO: Allow sourcetv only, not all bots */
   1.337 -		CPlayer *player = g_Players.GetPlayerByIndex(clients[i]);
   1.338 -		if (player->IsFakeClient())
   1.339 -		{
   1.340 -			continue;
   1.341 -		}
   1.342 -
   1.343 -		total++;
   1.344 -	}
   1.345 -
   1.346 -	if (!total)
   1.347 -	{
   1.348 -		/* End the broadcast here */
   1.349 -		handler->OnMenuEnd(menu);
   1.350 -		FreeBroadcastHandler(bh);
   1.351 -	}
   1.352 -
   1.353 -	return total;
   1.354 -}
   1.355 -
   1.356 -unsigned int MenuManager::VoteMenu(IBaseMenu *menu,
   1.357 -								   IMenuVoteHandler *handler,
   1.358 -								   int clients[],
   1.359 -								   unsigned int numClients,
   1.360 -								   unsigned int time)
   1.361 -{
   1.362 -	VoteHandler *vh;
   1.363 -
   1.364 -	if (m_VoteHandlers.empty())
   1.365 -	{
   1.366 -		vh = new VoteHandler(handler);
   1.367 -	} else {
   1.368 -		vh = m_VoteHandlers.front();
   1.369 -		m_VoteHandlers.pop();
   1.370 -		vh->m_pHandler = handler;
   1.371 -		vh->numClients = 0;
   1.372 -	}
   1.373 -
   1.374 -	vh->Initialize(menu);
   1.375 -	handler->OnMenuStart(menu);
   1.376 -
   1.377 -	unsigned int total = 0;
   1.378 -	for (unsigned int i=0; i<numClients; i++)
   1.379 -	{
   1.380 -		/* Only continue if displaying works */
   1.381 -		if (!menu->Display(clients[i], vh, time))
   1.382 -		{
   1.383 -			continue;
   1.384 -		}
   1.385 -
   1.386 -		/* :TODO: Allow sourcetv only, not all bots */
   1.387 -		CPlayer *player = g_Players.GetPlayerByIndex(clients[i]);
   1.388 -		if (player->IsFakeClient())
   1.389 -		{
   1.390 -			continue;
   1.391 -		}
   1.392 -
   1.393 -		total++;
   1.394 -	}
   1.395 -
   1.396 -	if (!total)
   1.397 -	{
   1.398 -		/* End the broadcast here */
   1.399 -		handler->OnMenuEnd(menu);
   1.400 -		FreeVoteHandler(vh);
   1.401 -	}
   1.402 -
   1.403 -	return total;
   1.404 -}
   1.405 -#endif
   1.406 -
   1.407 -void MenuManager::FreeBroadcastHandler(BroadcastHandler *bh)
   1.408 -{
   1.409 -	m_BroadcastHandlers.push(bh);
   1.410 -}
   1.411 -
   1.412 -void MenuManager::FreeVoteHandler(VoteHandler *vh)
   1.413 -{
   1.414 -	m_VoteHandlers.push(vh);
   1.415 -}
   1.416 -
   1.417  IMenuStyle *MenuManager::GetDefaultStyle()
   1.418  {
   1.419  	return m_pDefaultStyle;
   1.420  }
   1.421  
   1.422 +IVoteMenuHandler *MenuManager::CreateVoteWrapper(IMenuHandler *mh)
   1.423 +{
   1.424 +	VoteMenuHandler *vh = NULL;
   1.425 +
   1.426 +	if (m_VoteHandlers.empty())
   1.427 +	{
   1.428 +		vh = new VoteMenuHandler;
   1.429 +	} else {
   1.430 +		vh = m_VoteHandlers.front();
   1.431 +		m_VoteHandlers.pop();
   1.432 +	}
   1.433 +
   1.434 +	vh->Reset(mh);
   1.435 +
   1.436 +	return vh;
   1.437 +}
   1.438 +
   1.439 +void MenuManager::ReleaseVoteWrapper(IVoteMenuHandler *mh)
   1.440 +{
   1.441 +	if (mh == NULL)
   1.442 +	{
   1.443 +		return;
   1.444 +	}
   1.445 +
   1.446 +	m_VoteHandlers.push((VoteMenuHandler *)mh);
   1.447 +}
     2.1 --- a/core/MenuManager.h	Tue Jun 05 05:45:48 2007 +0000
     2.2 +++ b/core/MenuManager.h	Tue Jun 05 16:27:45 2007 +0000
     2.3 @@ -25,36 +25,36 @@
     2.4  using namespace SourceMod;
     2.5  using namespace SourceHook;
     2.6  
     2.7 -class BroadcastHandler : public IMenuHandler
     2.8 +class VoteMenuHandler : public IVoteMenuHandler
     2.9  {
    2.10 -public:
    2.11 -	BroadcastHandler(IMenuHandler *handler);
    2.12  public: //IMenuHandler
    2.13 +	unsigned int GetMenuAPIVersion2();
    2.14 +	void OnMenuStart(IBaseMenu *menu);
    2.15  	void OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display);
    2.16  	void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item);
    2.17 +	void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
    2.18  	void OnMenuEnd(IBaseMenu *menu);
    2.19 -	void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
    2.20 -	unsigned int GetMenuAPIVersion2();
    2.21 +	void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
    2.22 +	void OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display);
    2.23 +public: //IVoteMenuHandler
    2.24 +	bool IsVoteInProgress();
    2.25 +	void InitializeVoting(IBaseMenu *menu);
    2.26 +	void StartVoting();
    2.27  public:
    2.28 -	virtual void OnBroadcastEnd(IBaseMenu *menu);
    2.29 -public:
    2.30 +	void Reset(IMenuHandler *mh);
    2.31 +private:
    2.32 +	void DecrementPlayerCount();
    2.33 +	void EndVoting();
    2.34 +	void InternalReset();
    2.35 +private:
    2.36  	IMenuHandler *m_pHandler;
    2.37 -	unsigned int numClients;
    2.38 -};
    2.39 -
    2.40 -class VoteHandler : public BroadcastHandler
    2.41 -{
    2.42 -public:
    2.43 -	VoteHandler(IMenuVoteHandler *handler);
    2.44 -public:
    2.45 -	void Initialize(IBaseMenu *menu);
    2.46 -	void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item);
    2.47 -	void OnBroadcastEnd(IBaseMenu *menu);
    2.48 -private:
    2.49 -	CVector<unsigned int> m_counts;
    2.50 -	CVector<unsigned int> m_ties;
    2.51 -	unsigned int numItems;
    2.52 -	IMenuVoteHandler *m_pVoteHandler;
    2.53 +	unsigned int m_Clients;
    2.54 +	unsigned int m_Items;
    2.55 +	CVector<unsigned int> m_Votes;
    2.56 +	CVector<unsigned int> m_Dups;
    2.57 +	IBaseMenu *m_pCurMenu;
    2.58 +	bool m_bStarted;
    2.59 +	unsigned int m_NumVotes;
    2.60  };
    2.61  
    2.62  class MenuManager : 
    2.63 @@ -84,35 +84,24 @@
    2.64  	unsigned int GetStyleCount();
    2.65  	IMenuStyle *GetStyle(unsigned int index);
    2.66  	IMenuStyle *FindStyleByName(const char *name);
    2.67 -	unsigned int BroadcastMenu(IBaseMenu *menu, 
    2.68 -		IMenuHandler *handler,
    2.69 -		int clients[], 
    2.70 -		unsigned int numClients,
    2.71 -		unsigned int time);
    2.72 -	unsigned int VoteMenu(IBaseMenu *menu, 
    2.73 -		IMenuVoteHandler *handler,
    2.74 -		int clients[], 
    2.75 -		unsigned int numClients,
    2.76 -		unsigned int time);
    2.77  	IMenuStyle *GetDefaultStyle();
    2.78  	void AddStyle(IMenuStyle *style);
    2.79  	bool SetDefaultStyle(IMenuStyle *style);
    2.80  	IMenuPanel *RenderMenu(int client, menu_states_t &states, ItemOrder order);
    2.81 +	IVoteMenuHandler *CreateVoteWrapper(IMenuHandler *mh);
    2.82 +	void ReleaseVoteWrapper(IVoteMenuHandler *mh);
    2.83  public: //IHandleTypeDispatch
    2.84  	void OnHandleDestroy(HandleType_t type, void *object);
    2.85  public:
    2.86  	HandleError ReadMenuHandle(Handle_t handle, IBaseMenu **menu);
    2.87  	HandleError ReadStyleHandle(Handle_t handle, IMenuStyle **style);
    2.88  protected:
    2.89 -	void FreeBroadcastHandler(BroadcastHandler *bh);
    2.90 -	void FreeVoteHandler(VoteHandler *vh);
    2.91  	Handle_t CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner);
    2.92  	Handle_t CreateStyleHandle(IMenuStyle *style);
    2.93  private:
    2.94  	int m_ShowMenu;
    2.95  	IMenuStyle *m_pDefaultStyle;
    2.96 -	CStack<BroadcastHandler *> m_BroadcastHandlers;
    2.97 -	CStack<VoteHandler *> m_VoteHandlers;
    2.98 +	CStack<VoteMenuHandler *> m_VoteHandlers;
    2.99  	CVector<IMenuStyle *> m_Styles;
   2.100  	HandleType_t m_StyleType;
   2.101  	HandleType_t m_MenuType;
     3.1 --- a/core/MenuStyle_Base.cpp	Tue Jun 05 05:45:48 2007 +0000
     3.2 +++ b/core/MenuStyle_Base.cpp	Tue Jun 05 16:27:45 2007 +0000
     3.3 @@ -434,12 +434,14 @@
     3.4  CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) : 
     3.5  m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_ExitButton(true), 
     3.6  m_bShouldDelete(false), m_bCancelling(false), m_pOwner(pOwner ? pOwner : g_pCoreIdent), 
     3.7 -m_bDeleting(false), m_bWillFreeHandle(false), m_hHandle(BAD_HANDLE), m_pHandler(pHandler)
     3.8 +m_bDeleting(false), m_bWillFreeHandle(false), m_hHandle(BAD_HANDLE), m_pHandler(pHandler),
     3.9 +m_pVoteHandler(NULL)
    3.10  {
    3.11  }
    3.12  
    3.13  CBaseMenu::~CBaseMenu()
    3.14  {
    3.15 +	g_Menus.ReleaseVoteWrapper(m_pVoteHandler);
    3.16  }
    3.17  
    3.18  Handle_t CBaseMenu::GetHandle()
    3.19 @@ -647,3 +649,24 @@
    3.20  	delete this;
    3.21  }
    3.22  
    3.23 +bool CBaseMenu::BroadcastVote(int clients[], 
    3.24 +							  unsigned int numClients, 
    3.25 +							  unsigned int maxTime,
    3.26 +							  unsigned int flags)
    3.27 +{
    3.28 +	if (!m_pVoteHandler)
    3.29 +	{
    3.30 +		m_pVoteHandler = g_Menus.CreateVoteWrapper(m_pHandler);
    3.31 +	} else if (m_pVoteHandler->IsVoteInProgress()) {
    3.32 +		return false;
    3.33 +	}
    3.34 +
    3.35 +	m_pVoteHandler->InitializeVoting(this);
    3.36 +
    3.37 +	for (unsigned int i=0; i<numClients; i++)
    3.38 +	{
    3.39 +		VoteDisplay(clients[i], maxTime);
    3.40 +	}
    3.41 +
    3.42 +	m_pVoteHandler->StartVoting();
    3.43 +}
     4.1 --- a/core/MenuStyle_Base.h	Tue Jun 05 05:45:48 2007 +0000
     4.2 +++ b/core/MenuStyle_Base.h	Tue Jun 05 16:27:45 2007 +0000
     4.3 @@ -111,6 +111,12 @@
     4.4  	virtual void Destroy(bool releaseHandle);
     4.5  	virtual void Cancel_Finally() =0;
     4.6  	virtual Handle_t GetHandle();
     4.7 +	bool BroadcastVote(int clients[], 
     4.8 +		unsigned int numClients, 
     4.9 +		unsigned int maxTime,
    4.10 +		unsigned int flags=0);
    4.11 +public:
    4.12 +	virtual void VoteDisplay(int client, unsigned int maxTime) =0;
    4.13  private:
    4.14  	void InternalDelete();
    4.15  protected:
    4.16 @@ -127,6 +133,7 @@
    4.17  	bool m_bWillFreeHandle;
    4.18  	Handle_t m_hHandle;
    4.19  	IMenuHandler *m_pHandler;
    4.20 +	IVoteMenuHandler *m_pVoteHandler;
    4.21  };
    4.22  
    4.23  #endif //_INCLUDE_MENUSTYLE_BASE_H
     5.1 --- a/core/MenuStyle_Radio.cpp	Tue Jun 05 05:45:48 2007 +0000
     5.2 +++ b/core/MenuStyle_Radio.cpp	Tue Jun 05 16:27:45 2007 +0000
     5.3 @@ -366,9 +366,24 @@
     5.4  
     5.5  bool CRadioMenu::Display(int client, unsigned int time)
     5.6  {
     5.7 +	if (m_bCancelling)
     5.8 +	{
     5.9 +		return false;
    5.10 +	}
    5.11 +
    5.12  	return g_RadioMenuStyle.DoClientMenu(client, this, m_pHandler, time);
    5.13  }
    5.14  
    5.15 +void CRadioMenu::VoteDisplay(int client, unsigned int maxTime)
    5.16 +{
    5.17 +	if (m_bCancelling)
    5.18 +	{
    5.19 +		return;
    5.20 +	}
    5.21 +
    5.22 +	g_RadioMenuStyle.DoClientMenu(client, this, m_pVoteHandler, maxTime);
    5.23 +}
    5.24 +
    5.25  void CRadioMenu::Cancel_Finally()
    5.26  {
    5.27  	g_RadioMenuStyle.CancelMenu(this);
     6.1 --- a/core/MenuStyle_Radio.h	Tue Jun 05 05:45:48 2007 +0000
     6.2 +++ b/core/MenuStyle_Radio.h	Tue Jun 05 16:27:45 2007 +0000
     6.3 @@ -98,6 +98,7 @@
     6.4  	IMenuPanel *CreatePanel();
     6.5  	bool Display(int client, unsigned int time);
     6.6  	void Cancel_Finally();
     6.7 +	void VoteDisplay(int client, unsigned int maxTime);
     6.8  };
     6.9  
    6.10  extern CRadioStyle g_RadioMenuStyle;
     7.1 --- a/core/MenuStyle_Valve.cpp	Tue Jun 05 05:45:48 2007 +0000
     7.2 +++ b/core/MenuStyle_Valve.cpp	Tue Jun 05 16:27:45 2007 +0000
     7.3 @@ -375,6 +375,16 @@
     7.4  	return g_ValveMenuStyle.DoClientMenu(client, this, m_pHandler, time);
     7.5  }
     7.6  
     7.7 +void CValveMenu::VoteDisplay(int client, unsigned int maxTime)
     7.8 +{
     7.9 +	if (m_bCancelling)
    7.10 +	{
    7.11 +		return;
    7.12 +	}
    7.13 +
    7.14 +	g_ValveMenuStyle.DoClientMenu(client, this, m_pVoteHandler, maxTime);
    7.15 +}
    7.16 +
    7.17  IMenuPanel *CValveMenu::CreatePanel()
    7.18  {
    7.19  	return new CValveMenuDisplay(this);
     8.1 --- a/core/MenuStyle_Valve.h	Tue Jun 05 05:45:48 2007 +0000
     8.2 +++ b/core/MenuStyle_Valve.h	Tue Jun 05 16:27:45 2007 +0000
     8.3 @@ -103,6 +103,7 @@
     8.4  	bool SetExitButton(bool set);
     8.5  	bool SetPagination(unsigned int itemsPerPage);
     8.6  	bool Display(int client, unsigned int time);
     8.7 +	void VoteDisplay(int client, unsigned int maxTime);
     8.8  public: //CBaseMenu
     8.9  	void Cancel_Finally();
    8.10  private:
     9.1 --- a/public/IMenuManager.h	Tue Jun 05 05:45:48 2007 +0000
     9.2 +++ b/public/IMenuManager.h	Tue Jun 05 16:27:45 2007 +0000
     9.3 @@ -23,7 +23,7 @@
     9.4  #include <IHandleSys.h>
     9.5  
     9.6  #define SMINTERFACE_MENUMANAGER_NAME		"IMenuManager"
     9.7 -#define SMINTERFACE_MENUMANAGER_VERSION		1
     9.8 +#define SMINTERFACE_MENUMANAGER_VERSION		2
     9.9  
    9.10  /**
    9.11   * @file IMenuManager.h
    9.12 @@ -498,6 +498,23 @@
    9.13  		 * @return				Handle_t handle value.
    9.14  		 */
    9.15  		virtual Handle_t GetHandle() =0;
    9.16 +
    9.17 +		/**
    9.18 +		 * @brief Sends a menu to multiple clients as a vote menu.  All callbacks
    9.19 +		 * will be sent as normal, except two extras, OnMenuVoteStart and 
    9.20 +		 * OnMenuVoteEnd, will be called.
    9.21 +		 *
    9.22 +		 * @param clients		Array of client indexes.
    9.23 +		 * @param numClients	Number of client indexes in the array.
    9.24 +		 * @param maxTime		Maximum amount of time to hold the vote.
    9.25 +		 * @param flags			Optional voting flags (currently unused).
    9.26 +		 * @return				True on success, false if a vote is already in
    9.27 +		 *						progress (the menu must be cancelled first).
    9.28 +		 */
    9.29 +		virtual bool BroadcastVote(int clients[], 
    9.30 +			unsigned int numClients, 
    9.31 +			unsigned int maxTime,
    9.32 +			unsigned int flags=0) =0;
    9.33  	};
    9.34  
    9.35  	/** 
    9.36 @@ -600,21 +617,55 @@
    9.37  		virtual void OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display)
    9.38  		{
    9.39  		}
    9.40 -	};
    9.41  
    9.42 -	/** 
    9.43 -	 * @brief Handles a vote menu.
    9.44 -	 */
    9.45 -	class IMenuVoteHandler : public IMenuHandler
    9.46 -	{
    9.47 -	public:
    9.48  		/**
    9.49 -		 * @brief Called when a vote ends.
    9.50 +		 * @brief Called when a vote has been started and displayed to 
    9.51 +		 * clients.  This is called after OnMenuStart() and OnMenuDisplay(),
    9.52 +		 * but before OnMenuSelect().
    9.53 +		 *
    9.54 +		 * @param menu			Menu pointer.
    9.55 +		 */
    9.56 +		virtual void OnMenuVoteStart(IBaseMenu *menu)
    9.57 +		{
    9.58 +		}
    9.59 +
    9.60 +		/**
    9.61 +		 * @brief Called when a vote ends.  This is automatically called by the 
    9.62 +		 * wrapper, and never needs to called from a style implementation.
    9.63  		 *
    9.64  		 * @param menu			Menu pointer.
    9.65  		 * @param item			Item position that was chosen by a majority.
    9.66  		 */
    9.67 -		virtual void OnMenuVoteEnd(IBaseMenu *menu, unsigned int item) =0;
    9.68 +		virtual void OnMenuVoteEnd(IBaseMenu *menu, unsigned int item)
    9.69 +		{
    9.70 +		}
    9.71 +	};
    9.72 +
    9.73 +	/**
    9.74 +	 * @brief Contains functions for managing a vote handler.
    9.75 +	 */
    9.76 +	class IVoteMenuHandler : public IMenuHandler
    9.77 +	{
    9.78 +	public:
    9.79 +		/**
    9.80 +		 * @brief Returns whether or not a vote is in progress.
    9.81 +		 *
    9.82 +		 * @return				True if a vote is in progress, false otherwise.
    9.83 +		 */
    9.84 +		virtual bool IsVoteInProgress() =0;
    9.85 +
    9.86 +		/**
    9.87 +		 * @brief Use this to mark the vote as in progress (start).
    9.88 +		 *
    9.89 +		 * @param menu			Menu pointer.
    9.90 +		 */
    9.91 +		virtual void InitializeVoting(IBaseMenu *menu) =0;
    9.92 +
    9.93 +		/**
    9.94 +		 * @brief Use this to notify that all clients' displays have been
    9.95 +		 * processed (i.e., there are no more clients to display to).
    9.96 +		 */
    9.97 +		virtual void StartVoting() =0;
    9.98  	};
    9.99  
   9.100  	/**
   9.101 @@ -640,39 +691,6 @@
   9.102  		 */
   9.103  		virtual IMenuStyle *FindStyleByName(const char *name) =0;
   9.104  
   9.105 -#if 0
   9.106 -		/**
   9.107 -		 * @brief Broadcasts a menu to a number of clients.
   9.108 -		 *
   9.109 -		 * @param menu			Menu pointer.
   9.110 -		 * @param clients		Array of client indexes.
   9.111 -		 * @param numClients	Number of clients in the array.
   9.112 -		 * @param time			Time to hold the menu.
   9.113 -		 * @return				Number of clients the menu will be waiting on.
   9.114 -		 */
   9.115 -		virtual unsigned int BroadcastMenu(IBaseMenu *menu, 
   9.116 -									IMenuHandler *handler,
   9.117 -									int clients[], 
   9.118 -									unsigned int numClients,
   9.119 -									unsigned int time) =0;
   9.120 -
   9.121 -		/**
   9.122 -		 * @brief Broadcasts a menu to a number of clients as a vote menu.
   9.123 -		 *
   9.124 -		 * @param menu			Menu pointer.
   9.125 -		 * @param handler		IMenuHandler pointer.
   9.126 -		 * @param clients		Array of client indexes.
   9.127 -		 * @param numClients	Number of clients in the array.
   9.128 -		 * @param time			Time to hold the menu.
   9.129 -		 * @return				Number of clients the menu will be waiting on.
   9.130 -		 */
   9.131 -		virtual unsigned int VoteMenu(IBaseMenu *menu, 
   9.132 -									IMenuVoteHandler *handler,
   9.133 -									int clients[], 
   9.134 -									unsigned int numClients,
   9.135 -									unsigned int time) =0;
   9.136 -#endif
   9.137 -
   9.138  		/**
   9.139  		 * @brief Returns the default draw style Core is using.
   9.140  		 *
   9.141 @@ -695,6 +713,27 @@
   9.142  		 *						be freed using IMenuPanel::DeleteThis.
   9.143  		 */
   9.144  		virtual IMenuPanel *RenderMenu(int client, menu_states_t &states, ItemOrder order) =0;
   9.145 +
   9.146 +		/**
   9.147 +		 * @brief Creates a standard voting wrapper.  The wrapper is not 
   9.148 +		 * re-entrant; a second menu cannot be displayed on the same handler
   9.149 +		 * at the same time.
   9.150 +		 *
   9.151 +		 * @param mh			Menu handler to wrap around.
   9.152 +		 * @return				An IMenuHandler pointer that is a wrapper
   9.153 +		 *						around IMenuHandler callbacks to invoke
   9.154 +		 *						voting related callbacks.
   9.155 +		 */
   9.156 +		virtual IVoteMenuHandler *CreateVoteWrapper(IMenuHandler *mh) =0;
   9.157 +
   9.158 +		/**
   9.159 +		 * @brief Frees a standard voting wrapper.
   9.160 +		 *
   9.161 +		 * @param mh			Menu handler pointer created by 
   9.162 +		 *						CreateVoteWrapper().  NULL values will be 
   9.163 +		 *						safely ignored.
   9.164 +		 */
   9.165 +		virtual void ReleaseVoteWrapper(IVoteMenuHandler *mh) =0;
   9.166  	};
   9.167  }
   9.168