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