core/smn_menus.cpp
author David Anderson <dvander@alliedmods.net>
Sun Apr 06 07:13:00 2008 +0000 (2008-04-06)
changeset 1966 c869822c6a03
parent 1952 b7aa2b626807
child 2042 4a2faafca477
permissions -rw-r--r--
new makefile
ds@1952
     1
/**
ds@1952
     2
 * vim: set ts=4 :
ds@1952
     3
 * =============================================================================
ds@1952
     4
 * SourceMod
ds@1952
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1952
     6
 * =============================================================================
ds@1952
     7
 *
ds@1952
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1952
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1952
    10
 * Free Software Foundation.
ds@1952
    11
 * 
ds@1952
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1952
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1952
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1952
    15
 * details.
ds@1952
    16
 *
ds@1952
    17
 * You should have received a copy of the GNU General Public License along with
ds@1952
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
ds@1952
    19
 *
ds@1952
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1952
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1952
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1952
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1952
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1952
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1952
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1952
    27
 * or <http://www.sourcemod.net/license.php>.
ds@1952
    28
 *
ds@1952
    29
 * Version: $Id$
ds@1952
    30
 */
ds@1952
    31
ds@1952
    32
#include "sm_globals.h"
ds@1952
    33
#include <sh_stack.h>
ds@1952
    34
#include "DebugReporter.h"
ds@1952
    35
#include "MenuManager.h"
ds@1952
    36
#include "MenuStyle_Valve.h"
ds@1952
    37
#include "MenuStyle_Radio.h"
ds@1952
    38
#include "HandleSys.h"
ds@1952
    39
#include "PluginSys.h"
ds@1952
    40
#include "PlayerManager.h"
ds@1952
    41
#include "sm_stringutil.h"
ds@1952
    42
#include "sourcemm_api.h"
ds@1952
    43
#if defined MENU_DEBUG
ds@1952
    44
#include "Logger.h"
ds@1952
    45
#endif
ds@1952
    46
#include "ChatTriggers.h"
ds@1952
    47
ds@1952
    48
#if defined CreateMenu
ds@1952
    49
#undef CreateMenu
ds@1952
    50
#endif
ds@1952
    51
ds@1952
    52
/**
ds@1952
    53
 * And God said, "let there be menus," and behold, there were menus.  
ds@1952
    54
 * God saw the menus and they were good.  And the evening and the morning
ds@1952
    55
 * were the third day.
ds@1952
    56
 */
ds@1952
    57
ds@1952
    58
enum MenuAction
ds@1952
    59
{
ds@1952
    60
	MenuAction_Start = (1<<0),		/**< A menu has been started (nothing passed) */
ds@1952
    61
	MenuAction_Display = (1<<1),	/**< A menu is about to be displayed (param1=client, param2=MenuPanel Handle) */
ds@1952
    62
	MenuAction_Select = (1<<2),		/**< An item was selected (param1=client, param2=item) */
ds@1952
    63
	MenuAction_Cancel = (1<<3),		/**< The menu was cancelled (param1=client, param2=item) */
ds@1952
    64
	MenuAction_End = (1<<4),		/**< A menu's display/selection cycle is complete (nothing passed). */
ds@1952
    65
	MenuAction_VoteEnd = (1<<5),	/**< (VOTE ONLY): A vote sequence has ended (param1=chosen item) */
ds@1952
    66
	MenuAction_VoteStart = (1<<6), 	/**< (VOTE ONLY): A vote sequence has started */
ds@1952
    67
	MenuAction_VoteCancel = (1<<7),	/**< (VOTE ONLY): A vote sequence has been cancelled (nothing passed) */
ds@1952
    68
	MenuAction_DrawItem = (1<<8),	/**< A style is being drawn; return the new style (param1=client, param2=item) */
ds@1952
    69
	MenuAction_DisplayItem = (1<<9),	/**< the odd duck */
ds@1952
    70
};
ds@1952
    71
ds@1952
    72
class CPanelHandler : public IMenuHandler
ds@1952
    73
{
ds@1952
    74
	friend class MenuNativeHelpers;
ds@1952
    75
public:
ds@1952
    76
	CPanelHandler()
ds@1952
    77
	{
ds@1952
    78
	}
ds@1952
    79
	void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
ds@1952
    80
	void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item);
ds@1952
    81
private:
ds@1952
    82
	IPluginFunction *m_pFunc;
ds@1952
    83
	IPlugin *m_pPlugin;
ds@1952
    84
};
ds@1952
    85
ds@1952
    86
class CMenuHandler : public IMenuHandler
ds@1952
    87
{
ds@1952
    88
	friend class MenuNativeHelpers;
ds@1952
    89
public:
ds@1952
    90
	CMenuHandler(IPluginFunction *pBasic, int flags);
ds@1952
    91
public:
ds@1952
    92
	void OnMenuStart(IBaseMenu *menu);
ds@1952
    93
	void OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display);
ds@1952
    94
	void OnMenuSelect2(IBaseMenu *menu, int client, unsigned int item, unsigned int item_on_page);
ds@1952
    95
	void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
ds@1952
    96
	void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason);
ds@1952
    97
	void OnMenuDestroy(IBaseMenu *menu);
ds@1952
    98
	void OnMenuVoteStart(IBaseMenu *menu);
ds@1952
    99
	void OnMenuVoteResults(IBaseMenu *menu, const menu_vote_result_t *results);
ds@1952
   100
	void OnMenuVoteCancel(IBaseMenu *menu, VoteCancelReason reason);
ds@1952
   101
	void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
ds@1952
   102
	unsigned int OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr);
ds@1952
   103
	bool OnSetHandlerOption(const char *option, const void *data);
ds@1952
   104
#if 0
ds@1952
   105
	void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
ds@1952
   106
	void OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display);
ds@1952
   107
#endif
ds@1952
   108
private:
ds@1952
   109
	cell_t DoAction(IBaseMenu *menu, MenuAction action, cell_t param1, cell_t param2, cell_t def_res=0);
ds@1952
   110
private:
ds@1952
   111
	IPluginFunction *m_pBasic;
ds@1952
   112
	int m_Flags;
ds@1952
   113
	IPluginFunction *m_pVoteResults;
ds@1952
   114
	cell_t m_fnVoteResult;
ds@1952
   115
};
ds@1952
   116
ds@1952
   117
/**
ds@1952
   118
 * GLOBAL CLASS FOR HELPERS
ds@1952
   119
 */
ds@1952
   120
ds@1952
   121
class MenuNativeHelpers : 
ds@1952
   122
	public SMGlobalClass,
ds@1952
   123
	public IHandleTypeDispatch,
ds@1952
   124
	public IPluginsListener
ds@1952
   125
{
ds@1952
   126
public:
ds@1952
   127
	virtual void OnSourceModAllInitialized()
ds@1952
   128
	{
ds@1952
   129
		m_PanelType = g_HandleSys.CreateType("IMenuPanel", this, 0, NULL, NULL, g_pCoreIdent, NULL);
ds@1952
   130
		m_TempPanelType = g_HandleSys.CreateType("TempIMenuPanel", this, m_PanelType, NULL, NULL, g_pCoreIdent, NULL);
ds@1952
   131
		g_PluginSys.AddPluginsListener(this);
ds@1952
   132
	}
ds@1952
   133
ds@1952
   134
	virtual void OnSourceModShutdown()
ds@1952
   135
	{
ds@1952
   136
		g_HandleSys.RemoveType(m_TempPanelType, g_pCoreIdent);
ds@1952
   137
		g_HandleSys.RemoveType(m_PanelType, g_pCoreIdent);
ds@1952
   138
ds@1952
   139
		while (!m_FreePanelHandlers.empty())
ds@1952
   140
		{
ds@1952
   141
			delete m_FreePanelHandlers.front();
ds@1952
   142
			m_FreePanelHandlers.pop();
ds@1952
   143
		}
ds@1952
   144
ds@1952
   145
		while (!m_FreeMenuHandlers.empty())
ds@1952
   146
		{
ds@1952
   147
			delete m_FreeMenuHandlers.front();
ds@1952
   148
			m_FreeMenuHandlers.pop();
ds@1952
   149
		}
ds@1952
   150
	}
ds@1952
   151
ds@1952
   152
	virtual void OnHandleDestroy(HandleType_t type, void *object)
ds@1952
   153
	{
ds@1952
   154
		if (type == m_TempPanelType)
ds@1952
   155
		{
ds@1952
   156
			return;
ds@1952
   157
		}
ds@1952
   158
ds@1952
   159
		IMenuPanel *panel = (IMenuPanel *)object;
ds@1952
   160
		panel->DeleteThis();
ds@1952
   161
	}
ds@1952
   162
ds@1952
   163
	virtual bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
ds@1952
   164
	{
ds@1952
   165
		*pSize = ((IMenuPanel *)object)->GetApproxMemUsage();
ds@1952
   166
		return true;
ds@1952
   167
	}
ds@1952
   168
ds@1952
   169
	/**
ds@1952
   170
	 * It is extremely important that unloaded plugins don't crash.
ds@1952
   171
	 * Thus, if a plugin unloads, we run through every handler we have.
ds@1952
   172
	 * This means we do almost no runtime work for keeping track of
ds@1952
   173
	 * our panel handlers (we don't have to store a list of the running 
ds@1952
   174
	 * ones), but when push comes to shove, we have to scan them all
ds@1952
   175
	 * in case any of them are active.
ds@1952
   176
	 */
ds@1952
   177
	virtual void OnPluginUnloaded(IPlugin *plugin)
ds@1952
   178
	{
ds@1952
   179
		for (size_t i = 0; i < m_PanelHandlers.size(); i++)
ds@1952
   180
		{
ds@1952
   181
			if (m_PanelHandlers[i]->m_pPlugin == plugin)
ds@1952
   182
			{
ds@1952
   183
				m_PanelHandlers[i]->m_pPlugin = NULL;
ds@1952
   184
				m_PanelHandlers[i]->m_pFunc = NULL;
ds@1952
   185
			}
ds@1952
   186
		}
ds@1952
   187
	}
ds@1952
   188
ds@1952
   189
	inline HandleType_t GetPanelType()
ds@1952
   190
	{
ds@1952
   191
		return m_PanelType;
ds@1952
   192
	}
ds@1952
   193
ds@1952
   194
	inline HandleType_t GetTempPanelType()
ds@1952
   195
	{
ds@1952
   196
		return m_TempPanelType;
ds@1952
   197
	}
ds@1952
   198
ds@1952
   199
	CPanelHandler *GetPanelHandler(IPluginFunction *pFunction)
ds@1952
   200
	{
ds@1952
   201
		CPanelHandler *handler;
ds@1952
   202
		if (m_FreePanelHandlers.empty())
ds@1952
   203
		{
ds@1952
   204
			handler = new CPanelHandler;
ds@1952
   205
			m_PanelHandlers.push_back(handler);
ds@1952
   206
		} else {
ds@1952
   207
			handler = m_FreePanelHandlers.front();
ds@1952
   208
			m_FreePanelHandlers.pop();
ds@1952
   209
		}
ds@1952
   210
		handler->m_pFunc = pFunction;
ds@1952
   211
		handler->m_pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
ds@1952
   212
		return handler;
ds@1952
   213
	}
ds@1952
   214
ds@1952
   215
	void FreePanelHandler(CPanelHandler *handler)
ds@1952
   216
	{
ds@1952
   217
		handler->m_pFunc = NULL;
ds@1952
   218
		handler->m_pPlugin = NULL;
ds@1952
   219
		m_FreePanelHandlers.push(handler);
ds@1952
   220
	}
ds@1952
   221
ds@1952
   222
	CMenuHandler *GetMenuHandler(IPluginFunction *pFunction, int flags)
ds@1952
   223
	{
ds@1952
   224
		CMenuHandler *handler;
ds@1952
   225
		if (m_FreeMenuHandlers.empty())
ds@1952
   226
		{
ds@1952
   227
			handler = new CMenuHandler(pFunction, flags);
ds@1952
   228
		} else {
ds@1952
   229
			handler = m_FreeMenuHandlers.front();
ds@1952
   230
			m_FreeMenuHandlers.pop();
ds@1952
   231
			handler->m_pBasic = pFunction;
ds@1952
   232
			handler->m_Flags = flags;
ds@1952
   233
			handler->m_pVoteResults = NULL;
ds@1952
   234
		}
ds@1952
   235
		return handler;
ds@1952
   236
	}
ds@1952
   237
ds@1952
   238
	void FreeMenuHandler(CMenuHandler *handler)
ds@1952
   239
	{
ds@1952
   240
		m_FreeMenuHandlers.push(handler);
ds@1952
   241
	}
ds@1952
   242
ds@1952
   243
private:
ds@1952
   244
	HandleType_t m_PanelType;
ds@1952
   245
	HandleType_t m_TempPanelType;
ds@1952
   246
	CStack<CPanelHandler *> m_FreePanelHandlers;
ds@1952
   247
	CStack<CMenuHandler *> m_FreeMenuHandlers;
ds@1952
   248
	CVector<CPanelHandler *> m_PanelHandlers;
ds@1952
   249
} g_MenuHelpers;
ds@1952
   250
ds@1952
   251
/**
ds@1952
   252
 * BASIC PANEL HANDLER WRAPPER
ds@1952
   253
 */
ds@1952
   254
ds@1952
   255
void CPanelHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
ds@1952
   256
{
ds@1952
   257
	if (m_pFunc)
ds@1952
   258
	{
ds@1952
   259
		m_pFunc->PushCell(BAD_HANDLE);
ds@1952
   260
		m_pFunc->PushCell(MenuAction_Cancel);
ds@1952
   261
		m_pFunc->PushCell(client);
ds@1952
   262
		m_pFunc->PushCell(reason);
ds@1952
   263
		m_pFunc->Execute(NULL);
ds@1952
   264
	}
ds@1952
   265
	g_MenuHelpers.FreePanelHandler(this);
ds@1952
   266
}
ds@1952
   267
ds@1952
   268
void CPanelHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
ds@1952
   269
{
ds@1952
   270
	if (m_pFunc)
ds@1952
   271
	{
ds@1952
   272
		unsigned int old_reply = g_ChatTriggers.SetReplyTo(SM_REPLY_CHAT);
ds@1952
   273
		m_pFunc->PushCell(BAD_HANDLE);
ds@1952
   274
		m_pFunc->PushCell(MenuAction_Select);
ds@1952
   275
		m_pFunc->PushCell(client);
ds@1952
   276
		m_pFunc->PushCell(item);
ds@1952
   277
		m_pFunc->Execute(NULL);
ds@1952
   278
		g_ChatTriggers.SetReplyTo(old_reply);
ds@1952
   279
	}
ds@1952
   280
	g_MenuHelpers.FreePanelHandler(this);
ds@1952
   281
}
ds@1952
   282
ds@1952
   283
static IMenuPanel *s_pCurPanel = NULL;
ds@1952
   284
static unsigned int s_CurPanelReturn = 0;
ds@1952
   285
static const ItemDrawInfo *s_CurDrawInfo = NULL;
ds@1952
   286
static unsigned int *s_CurSelectPosition = NULL;
ds@1952
   287
ds@1952
   288
/**
ds@1952
   289
 * MENU HANDLER WRAPPER
ds@1952
   290
 */
ds@1952
   291
CMenuHandler::CMenuHandler(IPluginFunction *pBasic, int flags) : 
ds@1952
   292
	m_pBasic(pBasic), m_Flags(flags), m_pVoteResults(NULL)
ds@1952
   293
{
ds@1952
   294
	/* :TODO: We can probably cache the handle ahead of time */
ds@1952
   295
}
ds@1952
   296
ds@1952
   297
void CMenuHandler::OnMenuStart(IBaseMenu *menu)
ds@1952
   298
{
ds@1952
   299
	if ((m_Flags & (int)MenuAction_Start) == (int)MenuAction_Start)
ds@1952
   300
	{
ds@1952
   301
		DoAction(menu, MenuAction_Start, 0, 0);
ds@1952
   302
	}
ds@1952
   303
}
ds@1952
   304
ds@1952
   305
void CMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *panel)
ds@1952
   306
{
ds@1952
   307
	if ((m_Flags & (int)MenuAction_Display) == (int)MenuAction_Display)
ds@1952
   308
	{
ds@1952
   309
		HandleSecurity sec;
ds@1952
   310
		sec.pIdentity = g_pCoreIdent;
ds@1952
   311
		sec.pOwner = m_pBasic->GetParentContext()->GetIdentity();
ds@1952
   312
	
ds@1952
   313
		HandleAccess access;
ds@1952
   314
		g_HandleSys.InitAccessDefaults(NULL, &access);
ds@1952
   315
		access.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
ds@1952
   316
ds@1952
   317
		Handle_t hndl = g_HandleSys.CreateHandleEx(g_MenuHelpers.GetTempPanelType(), panel, &sec, &access, NULL);
ds@1952
   318
ds@1952
   319
		DoAction(menu, MenuAction_Display, client, hndl);
ds@1952
   320
ds@1952
   321
		g_HandleSys.FreeHandle(hndl, &sec);
ds@1952
   322
	}
ds@1952
   323
}
ds@1952
   324
ds@1952
   325
void CMenuHandler::OnMenuSelect2(IBaseMenu *menu, int client, unsigned int item, unsigned int item_on_page)
ds@1952
   326
{
ds@1952
   327
	/* Save old position first. */
ds@1952
   328
	unsigned int first_item = item_on_page;
ds@1952
   329
	unsigned int *old_pos = s_CurSelectPosition;
ds@1952
   330
ds@1952
   331
	s_CurSelectPosition = &first_item;
ds@1952
   332
ds@1952
   333
	unsigned int old_reply = g_ChatTriggers.SetReplyTo(SM_REPLY_CHAT);
ds@1952
   334
	DoAction(menu, MenuAction_Select, client, item);
ds@1952
   335
	g_ChatTriggers.SetReplyTo(old_reply);
ds@1952
   336
ds@1952
   337
	s_CurSelectPosition = old_pos;
ds@1952
   338
}
ds@1952
   339
ds@1952
   340
void CMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
ds@1952
   341
{
ds@1952
   342
	unsigned int old_reply = g_ChatTriggers.SetReplyTo(SM_REPLY_CHAT);
ds@1952
   343
	DoAction(menu, MenuAction_Cancel, client, (cell_t)reason);
ds@1952
   344
	g_ChatTriggers.SetReplyTo(old_reply);
ds@1952
   345
}
ds@1952
   346
ds@1952
   347
void CMenuHandler::OnMenuEnd(IBaseMenu *menu, MenuEndReason reason)
ds@1952
   348
{
ds@1952
   349
	DoAction(menu, MenuAction_End, reason, 0);
ds@1952
   350
}
ds@1952
   351
ds@1952
   352
void CMenuHandler::OnMenuDestroy(IBaseMenu *menu)
ds@1952
   353
{
ds@1952
   354
	g_MenuHelpers.FreeMenuHandler(this);
ds@1952
   355
}
ds@1952
   356
ds@1952
   357
void CMenuHandler::OnMenuVoteStart(IBaseMenu *menu)
ds@1952
   358
{
ds@1952
   359
	DoAction(menu, MenuAction_VoteStart, 0, 0);
ds@1952
   360
}
ds@1952
   361
ds@1952
   362
void CMenuHandler::OnMenuVoteCancel(IBaseMenu *menu, VoteCancelReason reason)
ds@1952
   363
{
ds@1952
   364
	DoAction(menu, MenuAction_VoteCancel, reason, 0);
ds@1952
   365
}
ds@1952
   366
ds@1952
   367
void CMenuHandler::OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style)
ds@1952
   368
{
ds@1952
   369
	if ((m_Flags & (int)MenuAction_DrawItem) == (int)MenuAction_DrawItem)
ds@1952
   370
	{
ds@1952
   371
		cell_t result = DoAction(menu, MenuAction_DrawItem, client, item, style);
ds@1952
   372
		style = (unsigned int)result;
ds@1952
   373
	}
ds@1952
   374
}
ds@1952
   375
ds@1952
   376
unsigned int CMenuHandler::OnMenuDisplayItem(IBaseMenu *menu,
ds@1952
   377
									 int client,
ds@1952
   378
									 IMenuPanel *panel,
ds@1952
   379
									 unsigned int item,
ds@1952
   380
									 const ItemDrawInfo &dr)
ds@1952
   381
{
ds@1952
   382
	if ((m_Flags & (int)MenuAction_DisplayItem) == (int)MenuAction_DisplayItem)
ds@1952
   383
	{
ds@1952
   384
		IMenuPanel *oldpanel = s_pCurPanel;
ds@1952
   385
		unsigned int oldret = s_CurPanelReturn;
ds@1952
   386
		const ItemDrawInfo *oldinfo = s_CurDrawInfo;
ds@1952
   387
		s_pCurPanel = panel;
ds@1952
   388
		s_CurPanelReturn = 0;
ds@1952
   389
		s_CurDrawInfo = &dr;
ds@1952
   390
ds@1952
   391
		cell_t res = DoAction(menu, MenuAction_DisplayItem, client, item, 0);
ds@1952
   392
ds@1952
   393
		if (!res)
ds@1952
   394
		{
ds@1952
   395
			res = s_CurPanelReturn;
ds@1952
   396
		}
ds@1952
   397
ds@1952
   398
		s_pCurPanel = oldpanel;
ds@1952
   399
		s_CurPanelReturn = oldret;
ds@1952
   400
		s_CurDrawInfo = oldinfo;
ds@1952
   401
ds@1952
   402
		return res;
ds@1952
   403
	}
ds@1952
   404
ds@1952
   405
	return 0;
ds@1952
   406
}
ds@1952
   407
ds@1952
   408
cell_t CMenuHandler::DoAction(IBaseMenu *menu, MenuAction action, cell_t param1, cell_t param2, cell_t def_res)
ds@1952
   409
{
ds@1952
   410
#if defined MENU_DEBUG
ds@1952
   411
	g_Logger.LogMessage("[SM_MENU] CMenuHandler::DoAction() (menu %p/%08x) (action %d) (param1 %d) (param2 %d)",
ds@1952
   412
		menu,
ds@1952
   413
		menu->GetHandle(),
ds@1952
   414
		action,
ds@1952
   415
		param1,
ds@1952
   416
		param2);
ds@1952
   417
#endif
ds@1952
   418
	cell_t res = def_res;
ds@1952
   419
	m_pBasic->PushCell(menu->GetHandle());
ds@1952
   420
	m_pBasic->PushCell((cell_t)action);
ds@1952
   421
	m_pBasic->PushCell(param1);
ds@1952
   422
	m_pBasic->PushCell(param2);
ds@1952
   423
	m_pBasic->Execute(&res);
ds@1952
   424
	return res;
ds@1952
   425
}
ds@1952
   426
ds@1952
   427
void CMenuHandler::OnMenuVoteResults(IBaseMenu *menu, const menu_vote_result_t *results)
ds@1952
   428
{
ds@1952
   429
	if (!m_pVoteResults)
ds@1952
   430
	{
ds@1952
   431
		/* Call MenuAction_VoteEnd instead.  See if there are any extra winners. */
ds@1952
   432
		unsigned int num_items = 1;
ds@1952
   433
		for (unsigned int i=1; i<results->num_items; i++)
ds@1952
   434
		{
ds@1952
   435
			if (results->item_list[i].count != results->item_list[0].count)
ds@1952
   436
			{
ds@1952
   437
				break;
ds@1952
   438
			}
ds@1952
   439
			num_items++;
ds@1952
   440
		}
ds@1952
   441
ds@1952
   442
		/* See if we need to pick a random winner. */
ds@1952
   443
		unsigned int winning_item;
ds@1952
   444
		if (num_items > 1)
ds@1952
   445
		{
ds@1952
   446
			/* Yes, we do. */
ds@1952
   447
			srand(time(NULL));
ds@1952
   448
			winning_item = rand() % num_items;
ds@1952
   449
			winning_item = results->item_list[winning_item].item;
ds@1952
   450
		} else {
ds@1952
   451
			/* No, take the first. */
ds@1952
   452
			winning_item = results->item_list[0].item;
ds@1952
   453
		}
ds@1952
   454
ds@1952
   455
		unsigned int total_votes = results->num_votes;
ds@1952
   456
		unsigned int winning_votes = results->item_list[0].count;
ds@1952
   457
ds@1952
   458
		DoAction(menu, MenuAction_VoteEnd, winning_item, (total_votes << 16) | (winning_votes & 0xFFFF));
ds@1952
   459
	} else {
ds@1952
   460
		IPluginContext *pContext = m_pVoteResults->GetParentContext();
ds@1952
   461
		bool no_call = false;
ds@1952
   462
		int err;
ds@1952
   463
ds@1952
   464
		/* First array */
ds@1952
   465
		cell_t client_array_address = -1;
ds@1952
   466
		cell_t *client_array_base = NULL;
ds@1952
   467
		cell_t client_array_size = results->num_clients + (results->num_clients * 2);
ds@1952
   468
		if (client_array_size)
ds@1952
   469
		{
ds@1952
   470
			if ((err = pContext->HeapAlloc(client_array_size, &client_array_address, &client_array_base))
ds@1952
   471
				!= SP_ERROR_NONE)
ds@1952
   472
			{
ds@1952
   473
				g_DbgReporter.GenerateError(pContext, m_fnVoteResult, err, "Menu callback could not allocate %d bytes for client list.", client_array_size * sizeof(cell_t));
ds@1952
   474
				no_call = true;
ds@1952
   475
			} else {
ds@1952
   476
				cell_t target_offs = sizeof(cell_t) * results->num_clients;
ds@1952
   477
				cell_t *cur_index = client_array_base;
ds@1952
   478
				cell_t *cur_array;
ds@1952
   479
				for (unsigned int i=0; i<results->num_clients; i++)
ds@1952
   480
				{
ds@1952
   481
					/* Copy the array index */
ds@1952
   482
					*cur_index = target_offs;
ds@1952
   483
					/* Get the current array address */
ds@1952
   484
					cur_array = (cell_t *)((char *)cur_index + target_offs);
ds@1952
   485
					/* Store information */
ds@1952
   486
					cur_array[0] = results->client_list[i].client;
ds@1952
   487
					cur_array[1] = results->client_list[i].item;
ds@1952
   488
					/* Adjust for the new target by subtracting one indirection
ds@1952
   489
					 * and adding one array.
ds@1952
   490
					 */
ds@1952
   491
					target_offs += (sizeof(cell_t) * 2) - sizeof(cell_t);
ds@1952
   492
					cur_index++;
ds@1952
   493
				}
ds@1952
   494
			}
ds@1952
   495
		}
ds@1952
   496
ds@1952
   497
		/* Second array */
ds@1952
   498
		cell_t item_array_address = -1;
ds@1952
   499
		cell_t *item_array_base = NULL;
ds@1952
   500
		cell_t item_array_size = results->num_items + (results->num_items * 2);
ds@1952
   501
		if (item_array_size)
ds@1952
   502
		{
ds@1952
   503
			if ((err = pContext->HeapAlloc(item_array_size, &item_array_address, &item_array_base))
ds@1952
   504
				!= SP_ERROR_NONE)
ds@1952
   505
			{
ds@1952
   506
				g_DbgReporter.GenerateError(pContext, m_fnVoteResult, err, "Menu callback could not allocate %d bytes for item list.", item_array_size);
ds@1952
   507
				no_call = true;
ds@1952
   508
			} else {
ds@1952
   509
				cell_t target_offs = sizeof(cell_t) * results->num_items;
ds@1952
   510
				cell_t *cur_index = item_array_base;
ds@1952
   511
				cell_t *cur_array;
ds@1952
   512
				for (unsigned int i=0; i<results->num_items; i++)
ds@1952
   513
				{
ds@1952
   514
					/* Copy the array index */
ds@1952
   515
					*cur_index = target_offs;
ds@1952
   516
					/* Get the current array address */
ds@1952
   517
					cur_array = (cell_t *)((char *)cur_index + target_offs);
ds@1952
   518
					/* Store information */
ds@1952
   519
					cur_array[0] = results->item_list[i].item;
ds@1952
   520
					cur_array[1] = results->item_list[i].count;
ds@1952
   521
					/* Adjust for the new target by subtracting one indirection
ds@1952
   522
					 * and adding one array.
ds@1952
   523
					 */
ds@1952
   524
					target_offs += (sizeof(cell_t) * 2) - sizeof(cell_t);
ds@1952
   525
					cur_index++;
ds@1952
   526
				}
ds@1952
   527
			}
ds@1952
   528
		}
ds@1952
   529
ds@1952
   530
		/* Finally, push everything */
ds@1952
   531
		if (!no_call)
ds@1952
   532
		{
ds@1952
   533
			m_pVoteResults->PushCell(menu->GetHandle());
ds@1952
   534
			m_pVoteResults->PushCell(results->num_votes);
ds@1952
   535
			m_pVoteResults->PushCell(results->num_clients);
ds@1952
   536
			m_pVoteResults->PushCell(client_array_address);
ds@1952
   537
			m_pVoteResults->PushCell(results->num_items);
ds@1952
   538
			m_pVoteResults->PushCell(item_array_address);
ds@1952
   539
			m_pVoteResults->Execute(NULL);
ds@1952
   540
		}
ds@1952
   541
ds@1952
   542
		/* Free what we allocated, in reverse order as required */
ds@1952
   543
		if (item_array_address != -1)
ds@1952
   544
		{
ds@1952
   545
			pContext->HeapPop(item_array_address);
ds@1952
   546
		}
ds@1952
   547
		if (client_array_address != -1)
ds@1952
   548
		{
ds@1952
   549
			pContext->HeapPop(client_array_address);
ds@1952
   550
		}
ds@1952
   551
	}
ds@1952
   552
}
ds@1952
   553
ds@1952
   554
bool CMenuHandler::OnSetHandlerOption(const char *option, const void *data)
ds@1952
   555
{
ds@1952
   556
	if (strcmp(option, "set_vote_results_handler") == 0)
ds@1952
   557
	{
ds@1952
   558
		void **array = (void **)data;
ds@1952
   559
		m_pVoteResults = (IPluginFunction *)array[0];
ds@1952
   560
		m_fnVoteResult = *(cell_t *)((cell_t *)array[1]);
ds@1952
   561
		return true;
ds@1952
   562
	}
ds@1952
   563
ds@1952
   564
	return false;
ds@1952
   565
}
ds@1952
   566
ds@1952
   567
/**
ds@1952
   568
 * INLINE FUNCTIONS FOR NATIVES
ds@1952
   569
 */
ds@1952
   570
ds@1952
   571
inline Handle_t MakePanelHandle(IMenuPanel *panel, IPluginContext *pContext)
ds@1952
   572
{
ds@1952
   573
	return g_HandleSys.CreateHandle(g_MenuHelpers.GetPanelType(), panel, pContext->GetIdentity(), g_pCoreIdent, NULL);
ds@1952
   574
}
ds@1952
   575
ds@1952
   576
inline HandleError ReadPanelHandle(Handle_t hndl, IMenuPanel **panel)
ds@1952
   577
{
ds@1952
   578
	HandleSecurity sec;
ds@1952
   579
	sec.pIdentity = g_pCoreIdent;
ds@1952
   580
	sec.pOwner = NULL;
ds@1952
   581
	return g_HandleSys.ReadHandle(hndl, g_MenuHelpers.GetPanelType(), &sec, (void **)panel);
ds@1952
   582
}
ds@1952
   583
ds@1952
   584
inline IMenuStyle *GetStyleFromCell(cell_t cell)
ds@1952
   585
{
ds@1952
   586
	enum MenuStyle
ds@1952
   587
	{
ds@1952
   588
		MenuStyle_Default = 0,		/**< The "default" menu style for the mod */
ds@1952
   589
		MenuStyle_Valve = 1,		/**< The Valve provided menu style (Used on HL2DM) */
ds@1952
   590
		MenuStyle_Radio = 2,		/**< The simpler menu style commonly used on CS:S */
ds@1952
   591
	};
ds@1952
   592
ds@1952
   593
	if (cell == MenuStyle_Valve)
ds@1952
   594
	{
ds@1952
   595
		return &g_ValveMenuStyle;
ds@1952
   596
	} else if (cell == MenuStyle_Radio
ds@1952
   597
			   && g_RadioMenuStyle.IsSupported())
ds@1952
   598
	{
ds@1952
   599
		return &g_RadioMenuStyle;
ds@1952
   600
	}
ds@1952
   601
ds@1952
   602
	return g_Menus.GetDefaultStyle();
ds@1952
   603
}
ds@1952
   604
ds@1952
   605
/***********************************
ds@1952
   606
 **** NATIVE DEFINITIONS ***********
ds@1952
   607
 ***********************************/
ds@1952
   608
ds@1952
   609
static cell_t CreateMenu(IPluginContext *pContext, const cell_t *params)
ds@1952
   610
{
ds@1952
   611
	IMenuStyle *style = g_Menus.GetDefaultStyle();
ds@1952
   612
	IPluginFunction *pFunction;
ds@1952
   613
ds@1952
   614
	if ((pFunction=pContext->GetFunctionById(params[1])) == NULL)
ds@1952
   615
	{
ds@1952
   616
		return pContext->ThrowNativeError("Function id %x is invalid", params[1]);
ds@1952
   617
	}
ds@1952
   618
ds@1952
   619
	CMenuHandler *handler = g_MenuHelpers.GetMenuHandler(pFunction, params[2]);
ds@1952
   620
	IBaseMenu *menu = style->CreateMenu(handler, pContext->GetIdentity());
ds@1952
   621
ds@1952
   622
	Handle_t hndl = menu->GetHandle();
ds@1952
   623
	if (!hndl)
ds@1952
   624
	{
ds@1952
   625
		menu->Destroy();
ds@1952
   626
		return BAD_HANDLE;
ds@1952
   627
	}
ds@1952
   628
ds@1952
   629
	return hndl;
ds@1952
   630
}
ds@1952
   631
ds@1952
   632
static cell_t DisplayMenu(IPluginContext *pContext, const cell_t *params)
ds@1952
   633
{
ds@1952
   634
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   635
	HandleError err;
ds@1952
   636
	IBaseMenu *menu;
ds@1952
   637
ds@1952
   638
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   639
	{
ds@1952
   640
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   641
	}
ds@1952
   642
ds@1952
   643
	return menu->Display(params[2], params[3]) ? 1 : 0;
ds@1952
   644
}
ds@1952
   645
ds@1952
   646
static cell_t DisplayMenuAtItem(IPluginContext *pContext, const cell_t *params)
ds@1952
   647
{
ds@1952
   648
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   649
	HandleError err;
ds@1952
   650
	IBaseMenu *menu;
ds@1952
   651
ds@1952
   652
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   653
	{
ds@1952
   654
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   655
	}
ds@1952
   656
ds@1952
   657
	return menu->DisplayAtItem(params[2], params[4], params[3]) ? 1 : 0;
ds@1952
   658
}
ds@1952
   659
ds@1952
   660
static cell_t VoteMenu(IPluginContext *pContext, const cell_t *params)
ds@1952
   661
{
ds@1952
   662
	if (g_Menus.IsVoteInProgress())
ds@1952
   663
	{
ds@1952
   664
		return pContext->ThrowNativeError("A vote is already in progress");
ds@1952
   665
	}
ds@1952
   666
ds@1952
   667
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   668
	HandleError err;
ds@1952
   669
	IBaseMenu *menu;
ds@1952
   670
ds@1952
   671
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   672
	{
ds@1952
   673
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   674
	}
ds@1952
   675
ds@1952
   676
	cell_t *addr;
ds@1952
   677
	pContext->LocalToPhysAddr(params[2], &addr);
ds@1952
   678
ds@1952
   679
	if (!g_Menus.StartVote(menu, params[3], addr, params[4]))
ds@1952
   680
	{
ds@1952
   681
		return 0;
ds@1952
   682
	}
ds@1952
   683
ds@1952
   684
	return 1;
ds@1952
   685
}
ds@1952
   686
ds@1952
   687
static cell_t AddMenuItem(IPluginContext *pContext, const cell_t *params)
ds@1952
   688
{
ds@1952
   689
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   690
	HandleError err;
ds@1952
   691
	IBaseMenu *menu;
ds@1952
   692
ds@1952
   693
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   694
	{
ds@1952
   695
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   696
	}
ds@1952
   697
ds@1952
   698
	char *info;
ds@1952
   699
	ItemDrawInfo dr;
ds@1952
   700
ds@1952
   701
	pContext->LocalToString(params[2], &info);
ds@1952
   702
	pContext->LocalToString(params[3], (char **)&dr.display);
ds@1952
   703
	dr.style = params[4];
ds@1952
   704
ds@1952
   705
	return menu->AppendItem(info, dr) ? 1 : 0;
ds@1952
   706
}
ds@1952
   707
ds@1952
   708
static cell_t InsertMenuItem(IPluginContext *pContext, const cell_t *params)
ds@1952
   709
{
ds@1952
   710
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   711
	HandleError err;
ds@1952
   712
	IBaseMenu *menu;
ds@1952
   713
ds@1952
   714
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   715
	{
ds@1952
   716
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   717
	}
ds@1952
   718
ds@1952
   719
	char *info;
ds@1952
   720
	ItemDrawInfo dr;
ds@1952
   721
ds@1952
   722
	pContext->LocalToString(params[3], &info);
ds@1952
   723
	pContext->LocalToString(params[4], (char **)&dr.display);
ds@1952
   724
	dr.style = params[5];
ds@1952
   725
ds@1952
   726
	return menu->InsertItem(params[2], info, dr) ? 1 : 0;
ds@1952
   727
}
ds@1952
   728
ds@1952
   729
static cell_t RemoveMenuItem(IPluginContext *pContext, const cell_t *params)
ds@1952
   730
{
ds@1952
   731
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   732
	HandleError err;
ds@1952
   733
	IBaseMenu *menu;
ds@1952
   734
ds@1952
   735
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   736
	{
ds@1952
   737
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   738
	}
ds@1952
   739
ds@1952
   740
	return menu->RemoveItem(params[2]) ? 1 : 0;
ds@1952
   741
}
ds@1952
   742
ds@1952
   743
static cell_t RemoveAllMenuItems(IPluginContext *pContext, const cell_t *params)
ds@1952
   744
{
ds@1952
   745
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   746
	HandleError err;
ds@1952
   747
	IBaseMenu *menu;
ds@1952
   748
ds@1952
   749
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   750
	{
ds@1952
   751
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   752
	}
ds@1952
   753
ds@1952
   754
	menu->RemoveAllItems();
ds@1952
   755
ds@1952
   756
	return 1;
ds@1952
   757
}
ds@1952
   758
ds@1952
   759
static cell_t GetMenuItem(IPluginContext *pContext, const cell_t *params)
ds@1952
   760
{
ds@1952
   761
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   762
	HandleError err;
ds@1952
   763
	IBaseMenu *menu;
ds@1952
   764
ds@1952
   765
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   766
	{
ds@1952
   767
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   768
	}
ds@1952
   769
ds@1952
   770
	ItemDrawInfo dr;
ds@1952
   771
	const char *info;
ds@1952
   772
ds@1952
   773
	if ((info=menu->GetItemInfo(params[2], &dr)) == NULL)
ds@1952
   774
	{
ds@1952
   775
		return 0;
ds@1952
   776
	}
ds@1952
   777
ds@1952
   778
	pContext->StringToLocalUTF8(params[3], params[4], info, NULL);
ds@1952
   779
	pContext->StringToLocalUTF8(params[6], params[7], dr.display ? dr.display : "", NULL);
ds@1952
   780
ds@1952
   781
	cell_t *addr;
ds@1952
   782
	pContext->LocalToPhysAddr(params[5], &addr);
ds@1952
   783
	*addr = dr.style;
ds@1952
   784
ds@1952
   785
	return 1;
ds@1952
   786
}
ds@1952
   787
ds@1952
   788
static cell_t SetMenuPagination(IPluginContext *pContext, const cell_t *params)
ds@1952
   789
{
ds@1952
   790
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   791
	HandleError err;
ds@1952
   792
	IBaseMenu *menu;
ds@1952
   793
ds@1952
   794
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   795
	{
ds@1952
   796
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   797
	}
ds@1952
   798
ds@1952
   799
	return menu->SetPagination(params[2]) ? 1 : 0;
ds@1952
   800
}
ds@1952
   801
ds@1952
   802
static cell_t GetMenuPagination(IPluginContext *pContext, const cell_t *params)
ds@1952
   803
{
ds@1952
   804
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   805
	HandleError err;
ds@1952
   806
	IBaseMenu *menu;
ds@1952
   807
ds@1952
   808
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   809
	{
ds@1952
   810
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   811
	}
ds@1952
   812
ds@1952
   813
	return menu->GetPagination();
ds@1952
   814
}
ds@1952
   815
ds@1952
   816
static cell_t GetMenuItemCount(IPluginContext *pContext, const cell_t *params)
ds@1952
   817
{
ds@1952
   818
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   819
	HandleError err;
ds@1952
   820
	IBaseMenu *menu;
ds@1952
   821
ds@1952
   822
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   823
	{
ds@1952
   824
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   825
	}
ds@1952
   826
ds@1952
   827
	return menu->GetItemCount();
ds@1952
   828
}
ds@1952
   829
ds@1952
   830
static cell_t SetMenuTitle(IPluginContext *pContext, const cell_t *params)
ds@1952
   831
{
ds@1952
   832
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   833
	HandleError err;
ds@1952
   834
	IBaseMenu *menu;
ds@1952
   835
ds@1952
   836
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   837
	{
ds@1952
   838
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   839
	}
ds@1952
   840
ds@1952
   841
	g_SourceMod.SetGlobalTarget(LANG_SERVER);
ds@1952
   842
ds@1952
   843
	char buffer[1024];
ds@1952
   844
	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
ds@1952
   845
ds@1952
   846
	menu->SetDefaultTitle(buffer);
ds@1952
   847
ds@1952
   848
	return 1;
ds@1952
   849
}
ds@1952
   850
ds@1952
   851
static cell_t GetMenuTitle(IPluginContext *pContext, const cell_t *params)
ds@1952
   852
{
ds@1952
   853
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   854
	HandleError err;
ds@1952
   855
	IBaseMenu *menu;
ds@1952
   856
ds@1952
   857
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   858
	{
ds@1952
   859
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   860
	}
ds@1952
   861
ds@1952
   862
	size_t written;
ds@1952
   863
	const char *title = menu->GetDefaultTitle();
ds@1952
   864
	pContext->StringToLocalUTF8(params[2], params[3], title, &written);
ds@1952
   865
ds@1952
   866
	return (cell_t)written;
ds@1952
   867
}
ds@1952
   868
ds@1952
   869
ds@1952
   870
static cell_t CreatePanelFromMenu(IPluginContext *pContext, const cell_t *params)
ds@1952
   871
{
ds@1952
   872
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   873
	HandleError err;
ds@1952
   874
	IBaseMenu *menu;
ds@1952
   875
ds@1952
   876
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   877
	{
ds@1952
   878
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   879
	}
ds@1952
   880
ds@1952
   881
	IMenuPanel *panel = menu->CreatePanel();
ds@1952
   882
	hndl = MakePanelHandle(panel, pContext);
ds@1952
   883
	if (!hndl)
ds@1952
   884
	{
ds@1952
   885
		panel->DeleteThis();
ds@1952
   886
	}
ds@1952
   887
ds@1952
   888
	return hndl;
ds@1952
   889
}
ds@1952
   890
ds@1952
   891
static cell_t GetMenuExitButton(IPluginContext *pContext, const cell_t *params)
ds@1952
   892
{
ds@1952
   893
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   894
	HandleError err;
ds@1952
   895
	IBaseMenu *menu;
ds@1952
   896
ds@1952
   897
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   898
	{
ds@1952
   899
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   900
	}
ds@1952
   901
ds@1952
   902
	return ((menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT) ? 1 : 0;
ds@1952
   903
}
ds@1952
   904
ds@1952
   905
static cell_t GetMenuExitBackButton(IPluginContext *pContext, const cell_t *params)
ds@1952
   906
{
ds@1952
   907
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   908
	HandleError err;
ds@1952
   909
	IBaseMenu *menu;
ds@1952
   910
ds@1952
   911
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   912
	{
ds@1952
   913
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   914
	}
ds@1952
   915
ds@1952
   916
	return ((menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXITBACK) == MENUFLAG_BUTTON_EXIT) ? 1 : 0;
ds@1952
   917
}
ds@1952
   918
ds@1952
   919
static cell_t SetMenuExitButton(IPluginContext *pContext, const cell_t *params)
ds@1952
   920
{
ds@1952
   921
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   922
	HandleError err;
ds@1952
   923
	IBaseMenu *menu;
ds@1952
   924
ds@1952
   925
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   926
	{
ds@1952
   927
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   928
	}
ds@1952
   929
ds@1952
   930
	unsigned int flags = menu->GetMenuOptionFlags();
ds@1952
   931
ds@1952
   932
	if (params[2])
ds@1952
   933
	{
ds@1952
   934
		flags |= MENUFLAG_BUTTON_EXIT;
ds@1952
   935
	} else {
ds@1952
   936
		flags &= ~MENUFLAG_BUTTON_EXIT;
ds@1952
   937
	}
ds@1952
   938
ds@1952
   939
	menu->SetMenuOptionFlags(flags);
ds@1952
   940
	unsigned int new_flags = menu->GetMenuOptionFlags();
ds@1952
   941
ds@1952
   942
	return (flags == new_flags);
ds@1952
   943
}
ds@1952
   944
ds@1952
   945
static cell_t SetMenuExitBackButton(IPluginContext *pContext, const cell_t *params)
ds@1952
   946
{
ds@1952
   947
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   948
	HandleError err;
ds@1952
   949
	IBaseMenu *menu;
ds@1952
   950
ds@1952
   951
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   952
	{
ds@1952
   953
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   954
	}
ds@1952
   955
ds@1952
   956
	unsigned int flags = menu->GetMenuOptionFlags();
ds@1952
   957
ds@1952
   958
	if (params[2])
ds@1952
   959
	{
ds@1952
   960
		flags |= MENUFLAG_BUTTON_EXITBACK;
ds@1952
   961
	} else {
ds@1952
   962
		flags &= ~MENUFLAG_BUTTON_EXITBACK;
ds@1952
   963
	}
ds@1952
   964
ds@1952
   965
	menu->SetMenuOptionFlags(flags);
ds@1952
   966
ds@1952
   967
	return 1;
ds@1952
   968
}
ds@1952
   969
ds@1952
   970
static cell_t CancelMenu(IPluginContext *pContext, const cell_t *params)
ds@1952
   971
{
ds@1952
   972
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   973
	HandleError err;
ds@1952
   974
	IBaseMenu *menu;
ds@1952
   975
ds@1952
   976
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   977
	{
ds@1952
   978
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
   979
	}
ds@1952
   980
ds@1952
   981
	g_Menus.CancelMenu(menu);
ds@1952
   982
ds@1952
   983
	return 1;
ds@1952
   984
}
ds@1952
   985
ds@1952
   986
static cell_t IsVoteInProgress(IPluginContext *pContext, const cell_t *params)
ds@1952
   987
{
ds@1952
   988
	return g_Menus.IsVoteInProgress() ? 1 : 0;
ds@1952
   989
}
ds@1952
   990
ds@1952
   991
static cell_t GetMenuStyle(IPluginContext *pContext, const cell_t *params)
ds@1952
   992
{
ds@1952
   993
	Handle_t hndl = (Handle_t)params[1];
ds@1952
   994
	HandleError err;
ds@1952
   995
	IBaseMenu *menu;
ds@1952
   996
ds@1952
   997
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
   998
	{
ds@1952
   999
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
  1000
	}
ds@1952
  1001
ds@1952
  1002
	return menu->GetDrawStyle()->GetHandle();
ds@1952
  1003
}
ds@1952
  1004
ds@1952
  1005
static cell_t GetMenuStyleHandle(IPluginContext *pContext, const cell_t *params)
ds@1952
  1006
{
ds@1952
  1007
	IMenuStyle *style = GetStyleFromCell(params[1]);
ds@1952
  1008
	if (!style)
ds@1952
  1009
	{
ds@1952
  1010
		return BAD_HANDLE;
ds@1952
  1011
	}
ds@1952
  1012
ds@1952
  1013
	return style->GetHandle();
ds@1952
  1014
}
ds@1952
  1015
ds@1952
  1016
static cell_t CreatePanel(IPluginContext *pContext, const cell_t *params)
ds@1952
  1017
{
ds@1952
  1018
	Handle_t hndl = (Handle_t)params[1];
ds@1952
  1019
	HandleError err;
ds@1952
  1020
	IMenuStyle *style;
ds@1952
  1021
ds@1952
  1022
	if (hndl != 0)
ds@1952
  1023
	{
ds@1952
  1024
		if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
ds@1952
  1025
		{
ds@1952
  1026
			return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
ds@1952
  1027
		}
ds@1952
  1028
	} else {
ds@1952
  1029
		style = g_Menus.GetDefaultStyle();
ds@1952
  1030
	}
ds@1952
  1031
ds@1952
  1032
	IMenuPanel *panel = style->CreatePanel();
ds@1952
  1033
ds@1952
  1034
	hndl = MakePanelHandle(panel, pContext);
ds@1952
  1035
	if (!hndl)
ds@1952
  1036
	{
ds@1952
  1037
		panel->DeleteThis();
ds@1952
  1038
		return BAD_HANDLE;
ds@1952
  1039
	}
ds@1952
  1040
ds@1952
  1041
	return hndl;
ds@1952
  1042
}
ds@1952
  1043
ds@1952
  1044
static cell_t CreateMenuEx(IPluginContext *pContext, const cell_t *params)
ds@1952
  1045
{
ds@1952
  1046
	Handle_t hndl = (Handle_t)params[1];
ds@1952
  1047
	HandleError err;
ds@1952
  1048
	IMenuStyle *style;
ds@1952
  1049
ds@1952
  1050
	if (hndl != 0)
ds@1952
  1051
	{
ds@1952
  1052
		if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
ds@1952
  1053
		{
ds@1952
  1054
			return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
ds@1952
  1055
		}
ds@1952
  1056
	} else {
ds@1952
  1057
		style = g_Menus.GetDefaultStyle();
ds@1952
  1058
	}
ds@1952
  1059
ds@1952
  1060
	IPluginFunction *pFunction;
ds@1952
  1061
	if ((pFunction=pContext->GetFunctionById(params[2])) == NULL)
ds@1952
  1062
	{
ds@1952
  1063
		return pContext->ThrowNativeError("Function id %x is invalid", params[2]);
ds@1952
  1064
	}
ds@1952
  1065
ds@1952
  1066
	CMenuHandler *handler = g_MenuHelpers.GetMenuHandler(pFunction, params[3]);
ds@1952
  1067
ds@1952
  1068
	IBaseMenu *pMenu = style->CreateMenu(handler, pContext->GetIdentity());
ds@1952
  1069
	hndl = pMenu->GetHandle();
ds@1952
  1070
	if (!hndl)
ds@1952
  1071
	{
ds@1952
  1072
		pMenu->Destroy();
ds@1952
  1073
		return BAD_HANDLE;
ds@1952
  1074
	}
ds@1952
  1075
ds@1952
  1076
	return hndl;
ds@1952
  1077
}
ds@1952
  1078
ds@1952
  1079
static cell_t GetClientMenu(IPluginContext *pContext, const cell_t *params)
ds@1952
  1080
{
ds@1952
  1081
	Handle_t hndl = (Handle_t)params[2];
ds@1952
  1082
	HandleError err;
ds@1952
  1083
	IMenuStyle *style;
ds@1952
  1084
ds@1952
  1085
	if (hndl != 0)
ds@1952
  1086
	{
ds@1952
  1087
		if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
ds@1952
  1088
		{
ds@1952
  1089
			return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
ds@1952
  1090
		}
ds@1952
  1091
	} else {
ds@1952
  1092
		style = g_Menus.GetDefaultStyle();
ds@1952
  1093
	}
ds@1952
  1094
ds@1952
  1095
	return style->GetClientMenu(params[1], NULL);
ds@1952
  1096
}
ds@1952
  1097
ds@1952
  1098
static cell_t CancelClientMenu(IPluginContext *pContext, const cell_t *params)
ds@1952
  1099
{
ds@1952
  1100
	Handle_t hndl = (Handle_t)params[3];
ds@1952
  1101
	HandleError err;
ds@1952
  1102
	IMenuStyle *style;
ds@1952
  1103
ds@1952
  1104
	if (hndl != 0)
ds@1952
  1105
	{
ds@1952
  1106
		if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
ds@1952
  1107
		{
ds@1952
  1108
			return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
ds@1952
  1109
		}
ds@1952
  1110
	} else {
ds@1952
  1111
		style = g_Menus.GetDefaultStyle();
ds@1952
  1112
	}
ds@1952
  1113
ds@1952
  1114
	return style->CancelClientMenu(params[1], params[2] ? true : false) ? 1 : 0;
ds@1952
  1115
}
ds@1952
  1116
ds@1952
  1117
static cell_t GetMaxPageItems(IPluginContext *pContext, const cell_t *params)
ds@1952
  1118
{
ds@1952
  1119
	Handle_t hndl = (Handle_t)params[1];
ds@1952
  1120
	HandleError err;
ds@1952
  1121
	IMenuStyle *style;
ds@1952
  1122
ds@1952
  1123
	if (hndl != 0)
ds@1952
  1124
	{
ds@1952
  1125
		if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
ds@1952
  1126
		{
ds@1952
  1127
			return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
ds@1952
  1128
		}
ds@1952
  1129
	} else {
ds@1952
  1130
		style = g_Menus.GetDefaultStyle();
ds@1952
  1131
	}
ds@1952
  1132
ds@1952
  1133
	return style->GetMaxPageItems();
ds@1952
  1134
}
ds@1952
  1135
ds@1952
  1136
static cell_t GetPanelStyle(IPluginContext *pContext, const cell_t *params)
ds@1952
  1137
{
ds@1952
  1138
	Handle_t hndl = (Handle_t)params[1];
ds@1952
  1139
	HandleError err;
ds@1952
  1140
	IMenuPanel *panel;
ds@1952
  1141
ds@1952
  1142
	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
ds@1952
  1143
	{
ds@1952
  1144
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
  1145
	}
ds@1952
  1146
ds@1952
  1147
	return panel->GetParentStyle()->GetHandle();
ds@1952
  1148
}
ds@1952
  1149
ds@1952
  1150
static cell_t SetPanelTitle(IPluginContext *pContext, const cell_t *params)
ds@1952
  1151
{
ds@1952
  1152
	Handle_t hndl = (Handle_t)params[1];
ds@1952
  1153
	HandleError err;
ds@1952
  1154
	IMenuPanel *panel;
ds@1952
  1155
ds@1952
  1156
	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
ds@1952
  1157
	{
ds@1952
  1158
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
  1159
	}
ds@1952
  1160
ds@1952
  1161
	char *text;
ds@1952
  1162
	pContext->LocalToString(params[2], &text);
ds@1952
  1163
ds@1952
  1164
	panel->DrawTitle(text, params[3] ? true : false);
ds@1952
  1165
ds@1952
  1166
	return 1;
ds@1952
  1167
}
ds@1952
  1168
ds@1952
  1169
static cell_t DrawPanelItem(IPluginContext *pContext, const cell_t *params)
ds@1952
  1170
{
ds@1952
  1171
	Handle_t hndl = (Handle_t)params[1];
ds@1952
  1172
	HandleError err;
ds@1952
  1173
	IMenuPanel *panel;
ds@1952
  1174
ds@1952
  1175
	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
ds@1952
  1176
	{
ds@1952
  1177
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
  1178
	}
ds@1952
  1179
ds@1952
  1180
	ItemDrawInfo dr;
ds@1952
  1181
	pContext->LocalToString(params[2], (char **)&dr.display);
ds@1952
  1182
	dr.style = params[3];
ds@1952
  1183
ds@1952
  1184
	return panel->DrawItem(dr);
ds@1952
  1185
}
ds@1952
  1186
ds@1952
  1187
static cell_t DrawPanelText(IPluginContext *pContext, const cell_t *params)
ds@1952
  1188
{
ds@1952
  1189
	Handle_t hndl = (Handle_t)params[1];
ds@1952
  1190
	HandleError err;
ds@1952
  1191
	IMenuPanel *panel;
ds@1952
  1192
ds@1952
  1193
	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
ds@1952
  1194
	{
ds@1952
  1195
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
  1196
	}
ds@1952
  1197
ds@1952
  1198
	char *text;
ds@1952
  1199
	pContext->LocalToString(params[2], &text);
ds@1952
  1200
ds@1952
  1201
	return panel->DrawRawLine(text) ? 1 : 0;
ds@1952
  1202
}
ds@1952
  1203
ds@1952
  1204
static cell_t CanPanelDrawFlags(IPluginContext *pContext, const cell_t *params)
ds@1952
  1205
{
ds@1952
  1206
	Handle_t hndl = (Handle_t)params[1];
ds@1952
  1207
	HandleError err;
ds@1952
  1208
	IMenuPanel *panel;
ds@1952
  1209
ds@1952
  1210
	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
ds@1952
  1211
	{
ds@1952
  1212
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
  1213
	}
ds@1952
  1214
ds@1952
  1215
	return panel->CanDrawItem(params[2]);
ds@1952
  1216
}
ds@1952
  1217
ds@1952
  1218
static cell_t SendPanelToClient(IPluginContext *pContext, const cell_t *params)
ds@1952
  1219
{
ds@1952
  1220
	Handle_t hndl = (Handle_t)params[1];
ds@1952
  1221
	HandleError err;
ds@1952
  1222
	IMenuPanel *panel;
ds@1952
  1223
ds@1952
  1224
	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
ds@1952
  1225
	{
ds@1952
  1226
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
  1227
	}
ds@1952
  1228
ds@1952
  1229
	IPluginFunction *pFunction;
ds@1952
  1230
	if ((pFunction=pContext->GetFunctionById(params[3])) == NULL)
ds@1952
  1231
	{
ds@1952
  1232
		return pContext->ThrowNativeError("Function id %x is invalid", params[3]);
ds@1952
  1233
	}
ds@1952
  1234
ds@1952
  1235
	CPanelHandler *handler = g_MenuHelpers.GetPanelHandler(pFunction);
ds@1952
  1236
	if (!panel->SendDisplay(params[2], handler, params[4]))
ds@1952
  1237
	{
ds@1952
  1238
		g_MenuHelpers.FreePanelHandler(handler);
ds@1952
  1239
	}
ds@1952
  1240
ds@1952
  1241
	return 1;
ds@1952
  1242
}
ds@1952
  1243
ds@1952
  1244
static cell_t SetPanelKeys(IPluginContext *pContext, const cell_t *params)
ds@1952
  1245
{
ds@1952
  1246
	Handle_t hndl = (Handle_t)params[1];
ds@1952
  1247
	HandleError err;
ds@1952
  1248
	IMenuPanel *panel;
ds@1952
  1249
ds@1952
  1250
	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
ds@1952
  1251
	{
ds@1952
  1252
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
  1253
	}
ds@1952
  1254
ds@1952
  1255
	return panel->SetSelectableKeys(params[2]);
ds@1952
  1256
}
ds@1952
  1257
ds@1952
  1258
static cell_t GetPanelCurrentKey(IPluginContext *pContext, const cell_t *params)
ds@1952
  1259
{
ds@1952
  1260
	Handle_t hndl = (Handle_t)params[1];
ds@1952
  1261
	HandleError err;
ds@1952
  1262
	IMenuPanel *panel;
ds@1952
  1263
ds@1952
  1264
	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
ds@1952
  1265
	{
ds@1952
  1266
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
  1267
	}
ds@1952
  1268
ds@1952
  1269
	return panel->GetCurrentKey();
ds@1952
  1270
}
ds@1952
  1271
ds@1952
  1272
static cell_t GetPanelTextRemaining(IPluginContext *pContext, const cell_t *params)
ds@1952
  1273
{
ds@1952
  1274
	Handle_t hndl = (Handle_t)params[1];
ds@1952
  1275
	HandleError err;
ds@1952
  1276
	IMenuPanel *panel;
ds@1952
  1277
ds@1952
  1278
	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
ds@1952
  1279
	{
ds@1952
  1280
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
  1281
	}
ds@1952
  1282
ds@1952
  1283
	return panel->GetAmountRemaining();
ds@1952
  1284
}
ds@1952
  1285
ds@1952
  1286
static cell_t SetPanelCurrentKey(IPluginContext *pContext, const cell_t *params)
ds@1952
  1287
{
ds@1952
  1288
	Handle_t hndl = (Handle_t)params[1];
ds@1952
  1289
	HandleError err;
ds@1952
  1290
	IMenuPanel *panel;
ds@1952
  1291
ds@1952
  1292
	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
ds@1952
  1293
	{
ds@1952
  1294
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
  1295
	}
ds@1952
  1296
ds@1952
  1297
	return panel->SetCurrentKey(params[2]) ? 1 : 0;
ds@1952
  1298
}
ds@1952
  1299
ds@1952
  1300
static cell_t RedrawMenuItem(IPluginContext *pContext, const cell_t *params)
ds@1952
  1301
{
ds@1952
  1302
	if (!s_pCurPanel)
ds@1952
  1303
	{
ds@1952
  1304
		return pContext->ThrowNativeError("You can only call this once from a MenuAction_DisplayItem callback");
ds@1952
  1305
	}
ds@1952
  1306
ds@1952
  1307
	char *str;
ds@1952
  1308
	pContext->LocalToString(params[1], &str);
ds@1952
  1309
ds@1952
  1310
	ItemDrawInfo dr = *s_CurDrawInfo;
ds@1952
  1311
	dr.display = str;
ds@1952
  1312
ds@1952
  1313
	if ((s_CurPanelReturn = s_pCurPanel->DrawItem(dr)) != 0)
ds@1952
  1314
	{
ds@1952
  1315
		s_pCurPanel = NULL;
ds@1952
  1316
	}
ds@1952
  1317
ds@1952
  1318
	return s_CurPanelReturn;
ds@1952
  1319
}
ds@1952
  1320
ds@1952
  1321
static cell_t GetMenuOptionFlags(IPluginContext *pContext, const cell_t *params)
ds@1952
  1322
{
ds@1952
  1323
	Handle_t hndl = (Handle_t)params[1];
ds@1952
  1324
	HandleError err;
ds@1952
  1325
	IBaseMenu *menu;
ds@1952
  1326
ds@1952
  1327
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
  1328
	{
ds@1952
  1329
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
  1330
	}
ds@1952
  1331
ds@1952
  1332
	return menu->GetMenuOptionFlags();
ds@1952
  1333
}
ds@1952
  1334
ds@1952
  1335
static cell_t SetMenuOptionFlags(IPluginContext *pContext, const cell_t *params)
ds@1952
  1336
{
ds@1952
  1337
	Handle_t hndl = (Handle_t)params[1];
ds@1952
  1338
	HandleError err;
ds@1952
  1339
	IBaseMenu *menu;
ds@1952
  1340
ds@1952
  1341
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
  1342
	{
ds@1952
  1343
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
  1344
	}
ds@1952
  1345
ds@1952
  1346
	menu->SetMenuOptionFlags(params[2]);
ds@1952
  1347
ds@1952
  1348
	return 1;
ds@1952
  1349
}
ds@1952
  1350
ds@1952
  1351
static cell_t CancelVote(IPluginContext *pContxt, const cell_t *params)
ds@1952
  1352
{
ds@1952
  1353
	if (!g_Menus.IsVoteInProgress())
ds@1952
  1354
	{
ds@1952
  1355
		return pContxt->ThrowNativeError("No vote is in progress");
ds@1952
  1356
	}
ds@1952
  1357
ds@1952
  1358
	g_Menus.CancelVoting();
ds@1952
  1359
ds@1952
  1360
	return 1;
ds@1952
  1361
}
ds@1952
  1362
ds@1952
  1363
static cell_t SetVoteResultCallback(IPluginContext *pContext, const cell_t *params)
ds@1952
  1364
{
ds@1952
  1365
	Handle_t hndl = (Handle_t)params[1];
ds@1952
  1366
	HandleError err;
ds@1952
  1367
	IBaseMenu *menu;
ds@1952
  1368
ds@1952
  1369
	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
ds@1952
  1370
	{
ds@1952
  1371
		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
ds@1952
  1372
	}
ds@1952
  1373
ds@1952
  1374
	IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
ds@1952
  1375
	if (!pFunction)
ds@1952
  1376
	{
ds@1952
  1377
		return pContext->ThrowNativeError("Invalid function %x", params[2]);
ds@1952
  1378
	}
ds@1952
  1379
ds@1952
  1380
	void *array[2];
ds@1952
  1381
	array[0] = pFunction;
ds@1952
  1382
	array[1] = (void *)&params[2];
ds@1952
  1383
ds@1952
  1384
	IMenuHandler *pHandler = menu->GetHandler();
ds@1952
  1385
	if (!pHandler->OnSetHandlerOption("set_vote_results_handler", (const void *)array))
ds@1952
  1386
	{
ds@1952
  1387
		return pContext->ThrowNativeError("The given menu does not support this option");
ds@1952
  1388
	}
ds@1952
  1389
ds@1952
  1390
	return 1;
ds@1952
  1391
}
ds@1952
  1392
ds@1952
  1393
static cell_t CheckVoteDelay(IPluginContext *pContext, const cell_t *params)
ds@1952
  1394
{
ds@1952
  1395
	return g_Menus.GetRemainingVoteDelay();
ds@1952
  1396
}
ds@1952
  1397
ds@1952
  1398
static cell_t GetMenuSelectionPosition(IPluginContext *pContext, const cell_t *params)
ds@1952
  1399
{
ds@1952
  1400
	if (!s_CurSelectPosition)
ds@1952
  1401
	{
ds@1952
  1402
		return pContext->ThrowNativeError("Can only be called from inside a MenuAction_Select callback");
ds@1952
  1403
	}
ds@1952
  1404
ds@1952
  1405
	return *s_CurSelectPosition;
ds@1952
  1406
}
ds@1952
  1407
ds@1952
  1408
class EmptyMenuHandler : public IMenuHandler
ds@1952
  1409
{
ds@1952
  1410
public:
ds@1952
  1411
} s_EmptyMenuHandler;
ds@1952
  1412
ds@1952
  1413
static cell_t InternalShowMenu(IPluginContext *pContext, const cell_t *params)
ds@1952
  1414
{
ds@1952
  1415
	int client = params[1];
ds@1952
  1416
	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
ds@1952
  1417
ds@1952
  1418
	if (pPlayer == NULL)
ds@1952
  1419
	{
ds@1952
  1420
		return pContext->ThrowNativeError("Invalid client index %d", client);
ds@1952
  1421
	}
ds@1952
  1422
	else if (!pPlayer->IsInGame())
ds@1952
  1423
	{
ds@1952
  1424
		return pContext->ThrowNativeError("Client %d is not in game", client);
ds@1952
  1425
	}
ds@1952
  1426
ds@1952
  1427
	if (!g_RadioMenuStyle.IsSupported())
ds@1952
  1428
	{
ds@1952
  1429
		return pContext->ThrowNativeError("Radio menus are not supported on this mod");
ds@1952
  1430
	}
ds@1952
  1431
ds@1952
  1432
	char *str;
ds@1952
  1433
	pContext->LocalToString(params[2], &str);
ds@1952
  1434
ds@1952
  1435
	IMenuPanel *pPanel = g_RadioMenuStyle.MakeRadioDisplay(str, params[4]);
ds@1952
  1436
ds@1952
  1437
	if (pPanel == NULL)
ds@1952
  1438
	{
ds@1952
  1439
		return 0;
ds@1952
  1440
	}
ds@1952
  1441
ds@1952
  1442
	IMenuHandler *pHandler;
ds@1952
  1443
	CPanelHandler *pActualHandler = NULL;
ds@1952
  1444
	if (params[5] != -1)
ds@1952
  1445
	{
ds@1952
  1446
		IPluginFunction *pFunction = pContext->GetFunctionById(params[5]);
ds@1952
  1447
		if (pFunction == NULL)
ds@1952
  1448
		{
ds@1952
  1449
			return pContext->ThrowNativeError("Invalid function index %x", params[5]);
ds@1952
  1450
		}
ds@1952
  1451
		pActualHandler = g_MenuHelpers.GetPanelHandler(pFunction);
ds@1952
  1452
	}
ds@1952
  1453
ds@1952
  1454
	if (pActualHandler == NULL)
ds@1952
  1455
	{
ds@1952
  1456
		pHandler = &s_EmptyMenuHandler;
ds@1952
  1457
	}
ds@1952
  1458
	else
ds@1952
  1459
	{
ds@1952
  1460
		pHandler = pActualHandler;
ds@1952
  1461
	}
ds@1952
  1462
ds@1952
  1463
	bool bSuccess = pPanel->SendDisplay(client, pHandler, params[3]);
ds@1952
  1464
ds@1952
  1465
	pPanel->DeleteThis();
ds@1952
  1466
ds@1952
  1467
	if (!bSuccess && pActualHandler != NULL)
ds@1952
  1468
	{
ds@1952
  1469
		g_MenuHelpers.FreePanelHandler(pActualHandler);
ds@1952
  1470
	}
ds@1952
  1471
ds@1952
  1472
	return bSuccess ? 1 : 0;
ds@1952
  1473
}
ds@1952
  1474
ds@1952
  1475
REGISTER_NATIVES(menuNatives)
ds@1952
  1476
{
ds@1952
  1477
	{"AddMenuItem",				AddMenuItem},
ds@1952
  1478
	{"CanPanelDrawFlags",		CanPanelDrawFlags},
ds@1952
  1479
	{"CancelClientMenu",		CancelClientMenu},
ds@1952
  1480
	{"CancelMenu",				CancelMenu},
ds@1952
  1481
	{"CancelVote",				CancelVote},
ds@1952
  1482
	{"CheckVoteDelay",			CheckVoteDelay},
ds@1952
  1483
	{"CreateMenu",				CreateMenu},
ds@1952
  1484
	{"CreateMenuEx",			CreateMenuEx},
ds@1952
  1485
	{"CreatePanel",				CreatePanel},
ds@1952
  1486
	{"CreatePanelFromMenu",		CreatePanelFromMenu},
ds@1952
  1487
	{"DisplayMenu",				DisplayMenu},
ds@1952
  1488
	{"DisplayMenuAtItem",		DisplayMenuAtItem},
ds@1952
  1489
	{"DrawPanelItem",			DrawPanelItem},
ds@1952
  1490
	{"DrawPanelText",			DrawPanelText},
ds@1952
  1491
	{"GetClientMenu",			GetClientMenu},
ds@1952
  1492
	{"GetMaxPageItems",			GetMaxPageItems},
ds@1952
  1493
	{"GetMenuExitBackButton",	GetMenuExitBackButton},
ds@1952
  1494
	{"GetMenuExitButton",		GetMenuExitButton},
ds@1952
  1495
	{"GetMenuItem",				GetMenuItem},
ds@1952
  1496
	{"GetMenuItemCount",		GetMenuItemCount},
ds@1952
  1497
	{"GetMenuOptionFlags",		GetMenuOptionFlags},
ds@1952
  1498
	{"GetMenuPagination",		GetMenuPagination},
ds@1952
  1499
	{"GetMenuSelectionPosition",GetMenuSelectionPosition},
ds@1952
  1500
	{"GetMenuStyle",			GetMenuStyle},
ds@1952
  1501
	{"GetMenuStyleHandle",		GetMenuStyleHandle},
ds@1952
  1502
	{"GetMenuTitle",			GetMenuTitle},
ds@1952
  1503
	{"GetPanelTextRemaining",	GetPanelTextRemaining},
ds@1952
  1504
	{"GetPanelCurrentKey",		GetPanelCurrentKey},
ds@1952
  1505
	{"GetPanelStyle",			GetPanelStyle},
ds@1952
  1506
	{"InsertMenuItem",			InsertMenuItem},
ds@1952
  1507
	{"InternalShowMenu",		InternalShowMenu},
ds@1952
  1508
	{"IsVoteInProgress",		IsVoteInProgress},
ds@1952
  1509
	{"RedrawMenuItem",			RedrawMenuItem},
ds@1952
  1510
	{"RemoveAllMenuItems",		RemoveAllMenuItems},
ds@1952
  1511
	{"RemoveMenuItem",			RemoveMenuItem},
ds@1952
  1512
	{"SendPanelToClient",		SendPanelToClient},
ds@1952
  1513
	{"SetMenuExitBackButton",	SetMenuExitBackButton},
ds@1952
  1514
	{"SetMenuExitButton",		SetMenuExitButton},
ds@1952
  1515
	{"SetMenuOptionFlags",		SetMenuOptionFlags},
ds@1952
  1516
	{"SetMenuPagination",		SetMenuPagination},
ds@1952
  1517
	{"SetMenuTitle",			SetMenuTitle},
ds@1952
  1518
	{"SetPanelCurrentKey",		SetPanelCurrentKey},
ds@1952
  1519
	{"SetPanelTitle",			SetPanelTitle},
ds@1952
  1520
	{"SetPanelKeys",			SetPanelKeys},
ds@1952
  1521
	{"SetVoteResultCallback",	SetVoteResultCallback},
ds@1952
  1522
	{"VoteMenu",				VoteMenu},
ds@1952
  1523
	{NULL,						NULL},
ds@1952
  1524
};