core/MenuStyle_Base.cpp
author Phong Dang <teame06@gmail.com>
Wed Aug 01 07:29:40 2007 +0000 (2007-08-01)
changeset 1241 2e8046793bc9
parent 1231 17badaf66ce4
child 1259 472c5e61cdc8
permissions -rw-r--r--
Added check to make sure player are alive to perform sm_slap, sm_burn, sm_slay.
     1 /**
     2  * vim: set ts=4 :
     3  * ================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     6  * ================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or 
     9  * modify it under the terms of the GNU General Public License, 
    10  * version 3.0, as published by the Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15  * GNU General Public License for more details.
    16  *
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to 
    21  * link the code of this program (as well as its derivative works) to 
    22  * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any 
    23  * Game MODs that run on software by the Valve Corporation.  You must 
    24  * obey the GNU General Public License in all respects for all other 
    25  * code used. Additionally, AlliedModders LLC grants this exception 
    26  * to all derivative works. AlliedModders LLC defines further 
    27  * exceptions, found in LICENSE.txt (as of this writing, version 
    28  * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
    29  *
    30  * Version: $Id$
    31  */
    32 
    33 #include <stdarg.h>
    34 #include "sm_stringutil.h"
    35 #include "MenuStyle_Base.h"
    36 #include "PlayerManager.h"
    37 #include "MenuManager.h"
    38 #include "HandleSys.h"
    39 #include "CellRecipientFilter.h"
    40 #if defined MENU_DEBUG
    41 #include "Logger.h"
    42 #endif
    43 
    44 BaseMenuStyle::BaseMenuStyle() : m_WatchList(256), m_hHandle(BAD_HANDLE)
    45 {
    46 }
    47 
    48 Handle_t BaseMenuStyle::GetHandle()
    49 {
    50 	/* Don't create the handle until we need it */
    51 	if (m_hHandle == BAD_HANDLE)
    52 	{
    53 		m_hHandle = g_Menus.CreateStyleHandle(this);
    54 	}
    55 
    56 	return m_hHandle;
    57 }
    58 
    59 void BaseMenuStyle::AddClientToWatch(int client)
    60 {
    61 #if defined MENU_DEBUG
    62 	g_Logger.LogMessage("[SM_MENU] AddClientToWatch(%d)", client);
    63 #endif
    64 	m_WatchList.push_back(client);
    65 }
    66 
    67 void BaseMenuStyle::RemoveClientFromWatch(int client)
    68 {
    69 #if defined MENU_DEBUG
    70 	g_Logger.LogMessage("[SM_MENU] RemoveClientFromWatch(%d)", client);
    71 #endif
    72 	m_WatchList.remove(client);
    73 }
    74 
    75 void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool bAutoIgnore/* =false */)
    76 {
    77 #if defined MENU_DEBUG
    78 	g_Logger.LogMessage("[SM_MENU] _CancelClientMenu() (client %d) (bAutoIgnore %d) (reason %d)", client, bAutoIgnore, reason);
    79 #endif
    80 	CBaseMenuPlayer *player = GetMenuPlayer(client);
    81 	menu_states_t &states = player->states;
    82 
    83 	bool bOldIgnore = player->bAutoIgnore;
    84 	if (bAutoIgnore)
    85 	{
    86 		player->bAutoIgnore = true;
    87 	}
    88 
    89 	/* Save states */
    90 	IMenuHandler *mh = states.mh;
    91 	IBaseMenu *menu = states.menu;
    92 
    93 	/* Clear menu */
    94 	player->bInMenu = false;
    95 	if (player->menuHoldTime)
    96 	{
    97 		RemoveClientFromWatch(client);
    98 	}
    99 
   100 	/* Fire callbacks */
   101 	mh->OnMenuCancel(menu, client, reason);
   102 	
   103 	/* Only fire end if there's a valid menu */
   104 	if (menu)
   105 	{
   106 		mh->OnMenuEnd(menu, MenuEnd_Cancelled);
   107 	}
   108 
   109 	if (bAutoIgnore)
   110 	{
   111 		player->bAutoIgnore = bOldIgnore;
   112 	}
   113 }
   114 
   115 void BaseMenuStyle::CancelMenu(CBaseMenu *menu)
   116 {
   117 #if defined MENU_DEBUG
   118 	g_Logger.LogMessage("[SM_MENU] CancelMenu() (menu %p)", menu);
   119 #endif
   120 	int maxClients = g_Players.GetMaxClients();
   121 	for (int i=1; i<=maxClients; i++)
   122 	{
   123 		CBaseMenuPlayer *player = GetMenuPlayer(i);
   124 		if (player->bInMenu)
   125 		{
   126 			menu_states_t &states = player->states;
   127 			if (states.menu == menu)
   128 			{
   129 				_CancelClientMenu(i, MenuCancel_Interrupted);
   130 			}
   131 		}
   132 	}
   133 }
   134 
   135 bool BaseMenuStyle::CancelClientMenu(int client, bool autoIgnore)
   136 {
   137 #if defined MENU_DEBUG
   138 	g_Logger.LogMessage("[SM_MENU] CancelClientMenu() (client %d) (bAutoIgnore %d)", client, autoIgnore);
   139 #endif
   140 	if (client < 1 || client > g_Players.MaxClients())
   141 	{
   142 		return false;
   143 	}
   144 
   145 	CBaseMenuPlayer *player = GetMenuPlayer(client);
   146 	if (!player->bInMenu)
   147 	{
   148 		return false;
   149 	}
   150 
   151 	_CancelClientMenu(client, MenuCancel_Interrupted, autoIgnore);
   152 
   153 	return true;
   154 }
   155 
   156 MenuSource BaseMenuStyle::GetClientMenu(int client, void **object)
   157 {
   158 	if (client < 1 || client > g_Players.GetMaxClients())
   159 	{
   160 		return MenuSource_None;
   161 	}
   162 
   163 	CBaseMenuPlayer *player = GetMenuPlayer(client);
   164 
   165 	if (player->bInMenu)
   166 	{
   167 		IBaseMenu *menu;
   168 		if ((menu=player->states.menu) != NULL)
   169 		{
   170 			if (object)
   171 			{
   172 				*object = menu;
   173 			}
   174 			return MenuSource_BaseMenu;
   175 		}
   176 
   177 		return MenuSource_Display;
   178 	} else if (player->bInExternMenu) {
   179 		if (player->menuHoldTime != 0
   180 			&& (gpGlobals->curtime > player->menuStartTime + player->menuHoldTime))
   181 		{
   182 			player->bInExternMenu = false;
   183 			return MenuSource_None;
   184 		}
   185 		return MenuSource_External;
   186 	}
   187 
   188 	return MenuSource_None;
   189 }
   190 
   191 void BaseMenuStyle::OnClientDisconnected(int client)
   192 {
   193 #if defined MENU_DEBUG
   194 	g_Logger.LogMessage("[SM_MENU] OnClientDisconnected(%d)", client);
   195 #endif
   196 	CBaseMenuPlayer *player = GetMenuPlayer(client);
   197 	if (!player->bInMenu)
   198 	{
   199 		return;
   200 	}
   201 
   202 	_CancelClientMenu(client, MenuCancel_Disconnected, true);
   203 
   204 	player->bInMenu = false;
   205 	player->bInExternMenu = false;
   206 }
   207 
   208 static int do_lookup[256];
   209 void BaseMenuStyle::ProcessWatchList()
   210 {
   211 	if (!m_WatchList.size())
   212 	{
   213 		return;
   214 	}
   215 
   216 #if defined MENU_DEBUG
   217 	g_Logger.LogMessage("BaseMenuStyle::ProcessWatchList(%d,%d,%d,%d,%d,%p)", 
   218 		m_WatchList.m_Size,
   219 		m_WatchList.m_FirstLink,
   220 		m_WatchList.m_FreeNodes,
   221 		m_WatchList.m_LastLink,
   222 		m_WatchList.m_MaxSize,
   223 		m_WatchList.m_Nodes);
   224 #endif
   225 
   226 	unsigned int total = 0;
   227 	for (FastLink<int>::iterator iter=m_WatchList.begin(); iter!=m_WatchList.end(); ++iter)
   228 	{
   229 		do_lookup[total++] = (*iter);
   230 	}
   231 
   232 #if defined MENU_DEBUG
   233 	if (total)
   234 	{
   235 		g_Logger.LogMessage("[SM_MENU] ProcessWatchList() found %d clients", total);
   236 	}
   237 #endif
   238 
   239 	int client;
   240 	CBaseMenuPlayer *player;
   241 	float curTime = gpGlobals->curtime;
   242 	for (unsigned int i=0; i<total; i++)
   243 	{
   244 		client = do_lookup[i];
   245 		player = GetMenuPlayer(client);
   246 #if defined MENU_DEBUG
   247 		g_Logger.LogMessage("[SM_MENU] ProcessWatchList() (client %d) (bInMenu %d) (menuHoldTime %d) (curTime %f) (menuStartTime %f)",
   248 			client,
   249 			player->bInMenu,
   250 			player->menuHoldTime,
   251 			curTime,
   252 			player->menuStartTime);
   253 #endif
   254 		if (!player->bInMenu || !player->menuHoldTime)
   255 		{
   256 #if defined MENU_DEBUG
   257 			g_Logger.LogMessage("[SM_MENU] ProcessWatchList() removing client %d", client);
   258 #endif
   259 			m_WatchList.remove(client);
   260 			continue;
   261 		}
   262 		if (curTime > player->menuStartTime + player->menuHoldTime)
   263 		{
   264 			_CancelClientMenu(client, MenuCancel_Timeout, false);
   265 		}
   266 	}
   267 }
   268 
   269 void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
   270 {
   271 #if defined MENU_DEBUG
   272 	g_Logger.LogMessage("[SM_MENU] ClientPressedKey() (client %d) (key_press %d)", client, key_press);
   273 #endif
   274 	CBaseMenuPlayer *player = GetMenuPlayer(client);
   275 
   276 	/* First question: Are we in a menu? */
   277 	if (!player->bInMenu)
   278 	{
   279 		return;
   280 	}
   281 
   282 	bool cancel = false;
   283 	unsigned int item = 0;
   284 	MenuCancelReason reason = MenuCancel_Exit;
   285 	MenuEndReason end_reason = MenuEnd_Selected;
   286 	menu_states_t &states = player->states;
   287 
   288 	assert(states.mh != NULL);
   289 
   290 	if (states.menu == NULL)
   291 	{
   292 		item = key_press;
   293 	} else if (key_press < 1 || key_press > GetMaxPageItems()) {
   294 		cancel = true;
   295 	} else {
   296 		ItemSelection type = states.slots[key_press].type;
   297 
   298 		/* Check if we should play a sound about the type */
   299 		if (g_Menus.MenuSoundsEnabled())
   300 		{
   301 			CellRecipientFilter filter;
   302 			cell_t clients[1];
   303 
   304 			clients[0] = client;
   305 			filter.Initialize(clients, 1);
   306 
   307 			const char *sound = g_Menus.GetMenuSound(type);
   308 
   309 			if (sound != NULL)
   310 			{
   311 				edict_t *pEdict = engine->PEntityOfEntIndex(client);
   312 				if (pEdict)
   313 				{
   314 					ICollideable *pCollideable = pEdict->GetCollideable();
   315 
   316 					if (pCollideable)
   317 					{
   318 						const Vector & pos = pCollideable->GetCollisionOrigin();
   319 		
   320 						enginesound->EmitSound(filter, 
   321 							client, 
   322 							CHAN_AUTO, 
   323 							sound, 
   324 							VOL_NORM, 
   325 							ATTN_NORM, 
   326 							0, 
   327 							PITCH_NORM, 
   328 							&pos);
   329 					}
   330 				}
   331 			}
   332 		}
   333 
   334 		/* For navigational items, we're going to redisplay */
   335 		if (type == ItemSel_Back)
   336 		{
   337 			if (!RedoClientMenu(client, ItemOrder_Descending))
   338 			{
   339 				cancel = true;
   340 				reason = MenuCancel_NoDisplay;
   341 				end_reason = MenuEnd_Cancelled;
   342 			} else {
   343 				return;
   344 			}
   345 		} else if (type == ItemSel_Next) {
   346 			if (!RedoClientMenu(client, ItemOrder_Ascending))
   347 			{
   348 				cancel = true;						/* I like Saltines. */
   349 				reason = MenuCancel_NoDisplay;
   350 				end_reason = MenuEnd_Cancelled;
   351 			} else {
   352 				return;
   353 			}
   354 		} else if (type == ItemSel_Exit || type == ItemSel_None) {
   355 			cancel = true;
   356 			reason = MenuCancel_Exit;
   357 			end_reason = MenuEnd_Exit;
   358 		} else if (type == ItemSel_ExitBack) {
   359 			cancel = true;
   360 			reason = MenuCancel_ExitBack;
   361 			end_reason = MenuEnd_ExitBack;
   362 		} else {
   363 			item = states.slots[key_press].item;
   364 		}
   365 	}
   366 
   367 	/* Save variables */
   368 	IMenuHandler *mh = states.mh;
   369 	IBaseMenu *menu = states.menu;
   370 
   371 	/* Clear states */
   372 	player->bInMenu = false;
   373 	if (player->menuHoldTime)
   374 	{
   375 		RemoveClientFromWatch(client);
   376 	}
   377 
   378 	if (cancel)
   379 	{
   380 		mh->OnMenuCancel(menu, client, reason);
   381 	} else {
   382 		mh->OnMenuSelect(menu, client, item);
   383 	}
   384 
   385 	/* Only fire end for valid menus */
   386 	if (menu)
   387 	{
   388 		mh->OnMenuEnd(menu, end_reason);
   389 	}
   390 }
   391 
   392 bool BaseMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time)
   393 {
   394 #if defined MENU_DEBUG
   395 	g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (panel %p) (mh %p) (time %d)",
   396 		client,
   397 		menu,
   398 		mh,
   399 		time);
   400 #endif
   401 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   402 	if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
   403 	{
   404 		return false;
   405 	}
   406 
   407 	CBaseMenuPlayer *player = GetMenuPlayer(client);
   408 	if (player->bAutoIgnore)
   409 	{
   410 		return false;
   411 	}
   412 
   413 	/* For the duration of this, we are going to totally ignore whether
   414 	* the player is already in a menu or not (except to cancel the old one).
   415 	* Instead, we are simply going to ignore any further menu displays, so
   416 	* this display can't be interrupted.
   417 	*/
   418 	player->bAutoIgnore = true;
   419 
   420 	/* Cancel any old menus */
   421 	menu_states_t &states = player->states;
   422 	if (player->bInMenu)
   423 	{
   424 		_CancelClientMenu(client, MenuCancel_Interrupted, true);
   425 	}
   426 
   427 	states.firstItem = 0;
   428 	states.lastItem = 0;
   429 	states.menu = NULL;
   430 	states.mh = mh;
   431 	states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
   432 	player->bInMenu = true;
   433 	player->bInExternMenu = false;
   434 	player->menuStartTime = gpGlobals->curtime;
   435 	player->menuHoldTime = time;
   436 
   437 	if (time)
   438 	{
   439 		AddClientToWatch(client);
   440 	}
   441 
   442 	/* Draw the display */
   443 	SendDisplay(client, menu);
   444 
   445 	/* We can be interrupted again! */
   446 	player->bAutoIgnore = false;
   447 
   448 	return true;
   449 }
   450 
   451 bool BaseMenuStyle::DoClientMenu(int client, CBaseMenu *menu, IMenuHandler *mh, unsigned int time)
   452 {
   453 #if defined MENU_DEBUG
   454 	g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (menu %p) (mh %p) (time %d)",
   455 		client,
   456 		menu,
   457 		mh,
   458 		time);
   459 #endif
   460 	mh->OnMenuStart(menu);
   461 
   462 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   463 	if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
   464 	{
   465 #if defined MENU_DEBUG
   466 		g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to display to client %d", client);
   467 #endif
   468 		mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
   469 		mh->OnMenuEnd(menu, MenuEnd_Cancelled);
   470 		return false;
   471 	}
   472 
   473 	CBaseMenuPlayer *player = GetMenuPlayer(client);
   474 	if (player->bAutoIgnore)
   475 	{
   476 #if defined MENU_DEBUG
   477 		g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Client %d is autoIgnoring", client);
   478 #endif
   479 		mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
   480 		mh->OnMenuEnd(menu, MenuEnd_Cancelled);
   481 		return false;
   482 	}
   483 
   484 	/* For the duration of this, we are going to totally ignore whether
   485 	 * the player is already in a menu or not (except to cancel the old one).
   486 	 * Instead, we are simply going to ignore any further menu displays, so
   487 	 * this display can't be interrupted.
   488 	 */
   489 	player->bAutoIgnore = true;
   490 
   491 	/* Cancel any old menus */
   492 	menu_states_t &states = player->states;
   493 	if (player->bInMenu)
   494 	{
   495 #if defined MENU_DEBUG
   496 		g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Cancelling old menu to client %d", client);
   497 #endif
   498 		_CancelClientMenu(client, MenuCancel_Interrupted, true);
   499 	}
   500 
   501 	states.firstItem = 0;
   502 	states.lastItem = 0;
   503 	states.menu = menu;
   504 	states.mh = mh;
   505 	states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
   506 
   507 	IMenuPanel *display = g_Menus.RenderMenu(client, states, ItemOrder_Ascending);
   508 	if (!display)
   509 	{
   510 #if defined MENU_DEBUG
   511 		g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to render to client %d", client);
   512 #endif
   513 		player->bAutoIgnore = false;
   514 		player->bInMenu = false;
   515 		mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
   516 		mh->OnMenuEnd(menu, MenuEnd_Cancelled);
   517 		return false;
   518 	}
   519 
   520 	/* Finally, set our states */
   521 	player->bInMenu = true;
   522 	player->bInExternMenu = false;
   523 	player->menuStartTime = gpGlobals->curtime;
   524 	player->menuHoldTime = time;
   525 
   526 	if (time)
   527 	{
   528 		AddClientToWatch(client);
   529 	}
   530 
   531 	/* Draw the display */
   532 	SendDisplay(client, display);
   533 
   534 	/* Free the display pointer */
   535 	display->DeleteThis();
   536 
   537 	/* We can be interrupted again! */
   538 	player->bAutoIgnore = false;
   539 
   540 #if defined MENU_DEBUG
   541 	g_Logger.LogMessage("[SM_MENU] DoClientMenu() finished successfully (client %d)", client);
   542 #endif
   543 
   544 	return true;
   545 }
   546 
   547 bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
   548 {
   549 #if defined MENU_DEBUG
   550 	g_Logger.LogMessage("[SM_MENU] RedoClientMenu() (client %d) (order %d)", client, order);
   551 #endif
   552 	CBaseMenuPlayer *player = GetMenuPlayer(client);
   553 	menu_states_t &states = player->states;
   554 
   555 	player->bAutoIgnore = true;
   556 	IMenuPanel *display = g_Menus.RenderMenu(client, states, order);
   557 	if (!display)
   558 	{
   559 #if defined MENU_DEBUG
   560 		g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Failed to render menu");
   561 #endif
   562 		if (player->menuHoldTime)
   563 		{
   564 			RemoveClientFromWatch(client);
   565 		}
   566 		player->bAutoIgnore = false;
   567 		return false;
   568 	}
   569 
   570 	SendDisplay(client, display);
   571 
   572 	display->DeleteThis();
   573 
   574 	player->bAutoIgnore = false;
   575 
   576 #if defined MENU_DEBUG
   577 	g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Succeeded to client %d", client);
   578 #endif
   579 
   580 	return true;
   581 }
   582 
   583 CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) : 
   584 m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_ExitButton(true), 
   585 m_bShouldDelete(false), m_bCancelling(false), m_pOwner(pOwner ? pOwner : g_pCoreIdent), 
   586 m_bDeleting(false), m_bWillFreeHandle(false), m_hHandle(BAD_HANDLE), m_pHandler(pHandler),
   587 m_pVoteHandler(NULL), m_ExitBackButton(false)
   588 {
   589 }
   590 
   591 CBaseMenu::~CBaseMenu()
   592 {
   593 	g_Menus.ReleaseVoteWrapper(m_pVoteHandler);
   594 }
   595 
   596 Handle_t CBaseMenu::GetHandle()
   597 {
   598 	if (!m_hHandle)
   599 	{
   600 		m_hHandle = g_Menus.CreateMenuHandle(this, m_pOwner);
   601 	}
   602 
   603 	return m_hHandle;
   604 }
   605 
   606 bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
   607 {
   608 	if (m_Pagination == (unsigned)MENU_NO_PAGINATION
   609 		&& m_items.size() >= m_pStyle->GetMaxPageItems())
   610 	{
   611 		return false;
   612 	}
   613 
   614 	CItem item;
   615 
   616 	item.infoString = m_Strings.AddString(info);
   617 	if (draw.display)
   618 	{
   619 		item.displayString = m_Strings.AddString(draw.display);
   620 	}
   621 	item.style = draw.style;
   622 	item.access = draw.access;
   623 
   624 
   625 	m_items.push_back(item);
   626 
   627 	return true;
   628 }
   629 
   630 bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw)
   631 {
   632 	if (m_Pagination == (unsigned)MENU_NO_PAGINATION
   633 		&& m_items.size() >= m_pStyle->GetMaxPageItems())
   634 	{
   635 		return false;
   636 	}
   637 
   638 	if (position >= m_items.size())
   639 	{
   640 		return false;
   641 	}
   642 
   643 	CItem item;
   644 	item.infoString = m_Strings.AddString(info);
   645 	if (draw.display)
   646 	{
   647 		item.displayString = m_Strings.AddString(draw.display);
   648 	}
   649 	item.style = draw.style;
   650 	item.access = draw.access;
   651 
   652 	CVector<CItem>::iterator iter = m_items.iterAt(position);
   653 	m_items.insert(iter, item);
   654 
   655 	return true;
   656 }
   657 
   658 bool CBaseMenu::RemoveItem(unsigned int position)
   659 {
   660 	if (position >= m_items.size())
   661 	{
   662 		return false;
   663 	}
   664 
   665 	m_items.erase(m_items.iterAt(position));
   666 
   667 	if (m_items.size() == 0)
   668 	{
   669 		m_Strings.Reset();
   670 	}
   671 
   672 	return true;
   673 }
   674 
   675 void CBaseMenu::RemoveAllItems()
   676 {
   677 	m_items.clear();
   678 	m_Strings.Reset();
   679 }
   680 
   681 const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */)
   682 {
   683 	if (position >= m_items.size())
   684 	{
   685 		return NULL;
   686 	}
   687 
   688 	if (draw)
   689 	{
   690 		draw->display = m_Strings.GetString(m_items[position].displayString);
   691 		draw->style = m_items[position].style;
   692 	}
   693 
   694 	return m_Strings.GetString(m_items[position].infoString);
   695 }
   696 
   697 unsigned int CBaseMenu::GetItemCount()
   698 {
   699 	return m_items.size();
   700 }
   701 
   702 bool CBaseMenu::SetPagination(unsigned int itemsPerPage)
   703 {
   704 	if (itemsPerPage > 7 || itemsPerPage == 1)
   705 	{
   706 		return false;
   707 	}
   708 
   709 	m_Pagination = itemsPerPage;
   710 
   711 	return true;
   712 }
   713 
   714 unsigned int CBaseMenu::GetPagination()
   715 {
   716 	return m_Pagination;
   717 }
   718 
   719 IMenuStyle *CBaseMenu::GetDrawStyle()
   720 {
   721 	return m_pStyle;
   722 }
   723 
   724 void CBaseMenu::SetDefaultTitle(const char *message)
   725 {
   726 	m_Title.assign(message);
   727 }
   728 
   729 const char *CBaseMenu::GetDefaultTitle()
   730 {
   731 	return m_Title.c_str();
   732 }
   733 
   734 bool CBaseMenu::GetExitButton()
   735 {
   736 	return m_ExitButton;
   737 }
   738 
   739 bool CBaseMenu::SetExitButton(bool set)
   740 {
   741 	m_ExitButton = set;
   742 	return true;
   743 }
   744 
   745 void CBaseMenu::Cancel()
   746 {
   747 	if (m_bCancelling)
   748 	{
   749 		return;
   750 	}
   751 
   752 #if defined MENU_DEBUG
   753 	g_Logger.LogMessage("[SM_MENU] CBaseMenu::Cancel(%p) (m_pVote %p) (inVote %d) (m_bShouldDelete %d)",
   754 		this,
   755 		m_pVoteHandler,
   756 		m_pVoteHandler ? m_pVoteHandler->IsVoteInProgress() : false,
   757 		m_bShouldDelete);
   758 #endif
   759 
   760 	if (m_pVoteHandler && m_pVoteHandler->IsVoteInProgress())
   761 	{
   762 		m_pVoteHandler->CancelVoting();
   763 	}
   764 
   765 	m_bCancelling = true;
   766 	Cancel_Finally();
   767 	m_bCancelling = false;
   768 
   769 	if (m_bShouldDelete)
   770 	{
   771 		InternalDelete();
   772 	}
   773 }
   774 
   775 void CBaseMenu::Destroy(bool releaseHandle)
   776 {
   777 	/* Check if we shouldn't be here */
   778 	if (m_bDeleting)
   779 	{
   780 		return;
   781 	}
   782 
   783 #if defined MENU_DEBUG
   784 	g_Logger.LogMessage("[SM_MENU] CBaseMenu::Destroy(%p) (release %d) (m_bCancelling %d) (m_bShouldDelete %d)",
   785 		this,
   786 		releaseHandle,
   787 		m_bCancelling,
   788 		m_bShouldDelete);
   789 #endif
   790 
   791 	/* Save the destruction hint about our handle */
   792 	m_bWillFreeHandle = releaseHandle;
   793 
   794 	/* Now actually do stuff */
   795 	if (!m_bCancelling || m_bShouldDelete)
   796 	{
   797 		Cancel();
   798 		InternalDelete();
   799 	} else {
   800 		m_bShouldDelete = true;
   801 	}
   802 }
   803 
   804 void CBaseMenu::InternalDelete()
   805 {
   806 	if (m_bWillFreeHandle && m_hHandle != BAD_HANDLE)
   807 	{
   808 		Handle_t hndl = m_hHandle;
   809 		HandleSecurity sec;
   810 
   811 		sec.pOwner = m_pOwner;
   812 		sec.pIdentity = g_pCoreIdent;
   813 
   814 		m_hHandle = BAD_HANDLE;
   815 		m_bDeleting = true;
   816 		g_HandleSys.FreeHandle(hndl, &sec);
   817 	}
   818 
   819 	m_pHandler->OnMenuDestroy(this);
   820 
   821 	delete this;
   822 }
   823 
   824 bool CBaseMenu::BroadcastVote(int clients[], 
   825 							  unsigned int numClients, 
   826 							  unsigned int maxTime,
   827 							  unsigned int flags)
   828 {
   829 #if defined MENU_DEBUG
   830 	g_Logger.LogMessage("[SM_MENU] CBaseMenu::BroadcastVote(%p) (maxTime %d) (numClients %d) (m_pVote %p) (inVote %d)",
   831 		this,
   832 		maxTime,
   833 		numClients,
   834 		m_pVoteHandler,
   835 		m_pVoteHandler ? m_pVoteHandler->IsVoteInProgress() : false);
   836 #endif
   837 	if (!m_pVoteHandler)
   838 	{
   839 		m_pVoteHandler = g_Menus.CreateVoteWrapper(m_pHandler);
   840 	} else if (m_pVoteHandler->IsVoteInProgress()) {
   841 		return false;
   842 	}
   843 
   844 	m_pVoteHandler->InitializeVoting(this);
   845 
   846 	for (unsigned int i=0; i<numClients; i++)
   847 	{
   848 		VoteDisplay(clients[i], maxTime);
   849 	}
   850 
   851 	m_pVoteHandler->StartVoting();
   852 
   853 	return true;
   854 }
   855 
   856 bool CBaseMenu::IsVoteInProgress()
   857 {
   858 	return (m_pVoteHandler && m_pVoteHandler->IsVoteInProgress());
   859 }
   860 
   861 bool CBaseMenu::GetExitBackButton()
   862 {
   863 	return m_ExitBackButton;
   864 }
   865 
   866 void CBaseMenu::SetExitBackButton(bool set)
   867 {
   868 	m_ExitBackButton = set;
   869 }