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