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