core/smn_menus.cpp
author David Anderson <dvander@alliedmods.net>
Fri Jun 08 05:11:49 2007 +0000 (2007-06-08)
changeset 927 a60cedac2a1a
parent 885 7767bebc6262
child 960 fad7c45dacf5
permissions -rw-r--r--
added another unban command and added forwards for banning (amb369)
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include "sm_globals.h"
    16 #include <sh_stack.h>
    17 #include "MenuManager.h"
    18 #include "MenuStyle_Valve.h"
    19 #include "MenuStyle_Radio.h"
    20 #include "HandleSys.h"
    21 #include "PluginSys.h"
    22 
    23 #if defined CreateMenu
    24 #undef CreateMenu
    25 #endif
    26 
    27 /**
    28  * And God said, "let there be menus," and behold, there were menus.  
    29  * God saw the menus and they were good.  And the evening and the morning
    30  * were the third day.
    31  */
    32 
    33 enum MenuAction
    34 {
    35 	MenuAction_Start = (1<<0),		/**< A menu has been started (nothing passed) */
    36 	MenuAction_Display = (1<<1),	/**< A menu is about to be displayed (param1=client, param2=MenuPanel Handle) */
    37 	MenuAction_Select = (1<<2),		/**< An item was selected (param1=client, param2=item) */
    38 	MenuAction_Cancel = (1<<3),		/**< The menu was cancelled (param1=client, param2=item) */
    39 	MenuAction_End = (1<<4),		/**< A menu's display/selection cycle is complete (nothing passed). */
    40 	MenuAction_VoteEnd = (1<<5),	/**< (VOTE ONLY): A vote sequence has ended (param1=chosen item) */
    41 	MenuAction_VoteStart = (1<<6), 	/**< (VOTE ONLY): A vote sequence has started */
    42 	MenuAction_VoteCancel = (1<<7),	/**< (VOTE ONLY): A vote sequence has been cancelled (nothing passed) */
    43 };
    44 
    45 class CPanelHandler : public IMenuHandler
    46 {
    47 	friend class MenuNativeHelpers;
    48 public:
    49 	CPanelHandler()
    50 	{
    51 	}
    52 	void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
    53 	void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item);
    54 private:
    55 	IPluginFunction *m_pFunc;
    56 	IPlugin *m_pPlugin;
    57 };
    58 
    59 class CMenuHandler : public IMenuHandler
    60 {
    61 	friend class MenuNativeHelpers;
    62 public:
    63 	CMenuHandler(IPluginFunction *pBasic, int flags);
    64 public:
    65 	void OnMenuStart(IBaseMenu *menu);
    66 	void OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display);
    67 	void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item);
    68 	void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
    69 	void OnMenuEnd(IBaseMenu *menu);
    70 	void OnMenuDestroy(IBaseMenu *menu);
    71 	void OnMenuVoteStart(IBaseMenu *menu);
    72 	void OnMenuVoteEnd(IBaseMenu *menu, unsigned int item);
    73 	void OnMenuVoteCancel(IBaseMenu *menu);
    74 #if 0
    75 	void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
    76 	void OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display);
    77 #endif
    78 private:
    79 	void DoAction(IBaseMenu *menu, MenuAction action, cell_t param1, cell_t param2);
    80 private:
    81 	IPluginFunction *m_pBasic;
    82 	int m_Flags;
    83 };
    84 
    85 /**
    86  * GLOBAL CLASS FOR HELPERS
    87  */
    88 
    89 class MenuNativeHelpers : 
    90 	public SMGlobalClass,
    91 	public IHandleTypeDispatch,
    92 	public IPluginsListener
    93 {
    94 public:
    95 	virtual void OnSourceModAllInitialized()
    96 	{
    97 		m_PanelType = g_HandleSys.CreateType("IMenuPanel", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    98 		g_PluginSys.AddPluginsListener(this);
    99 	}
   100 
   101 	virtual void OnSourceModShutdown()
   102 	{
   103 		g_HandleSys.RemoveType(m_PanelType, g_pCoreIdent);
   104 
   105 		while (!m_FreePanelHandlers.empty())
   106 		{
   107 			delete m_FreePanelHandlers.front();
   108 			m_FreePanelHandlers.pop();
   109 		}
   110 
   111 		while (!m_FreeMenuHandlers.empty())
   112 		{
   113 			delete m_FreeMenuHandlers.front();
   114 			m_FreeMenuHandlers.pop();
   115 		}
   116 	}
   117 
   118 	virtual void OnHandleDestroy(HandleType_t type, void *object)
   119 	{
   120 		IMenuPanel *panel = (IMenuPanel *)object;
   121 		panel->DeleteThis();
   122 	}
   123 
   124 	/**
   125 	 *   It is extremely important that unloaded plugins don't crash.
   126 	 * Thus, if a plugin unloads, we run through every handler we have.
   127 	 * This means we do almost no runtime work for keeping track of
   128 	 * our panel handlers (we don't have to store a list of the running 
   129 	 * ones), but when push comes to shove, we have to scan them all
   130 	 * in case any of them are active.
   131 	 */
   132 	virtual void OnPluginUnloaded(IPlugin *plugin)
   133 	{
   134 		for (size_t i = 0; i < m_PanelHandlers.size(); i++)
   135 		{
   136 			if (m_PanelHandlers[i]->m_pPlugin == plugin)
   137 			{
   138 				m_PanelHandlers[i]->m_pPlugin = NULL;
   139 				m_PanelHandlers[i]->m_pFunc = NULL;
   140 			}
   141 		}
   142 	}
   143 
   144 	inline HandleType_t GetPanelType()
   145 	{
   146 		return m_PanelType;
   147 	}
   148 
   149 	CPanelHandler *GetPanelHandler(IPluginFunction *pFunction)
   150 	{
   151 		CPanelHandler *handler;
   152 		if (m_FreePanelHandlers.empty())
   153 		{
   154 			handler = new CPanelHandler;
   155 			m_PanelHandlers.push_back(handler);
   156 		} else {
   157 			handler = m_FreePanelHandlers.front();
   158 			m_FreePanelHandlers.pop();
   159 		}
   160 		handler->m_pFunc = pFunction;
   161 		handler->m_pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
   162 		return handler;
   163 	}
   164 
   165 	void FreePanelHandler(CPanelHandler *handler)
   166 	{
   167 		handler->m_pFunc = NULL;
   168 		handler->m_pPlugin = NULL;
   169 		m_FreePanelHandlers.push(handler);
   170 	}
   171 
   172 	CMenuHandler *GetMenuHandler(IPluginFunction *pFunction, int flags)
   173 	{
   174 		CMenuHandler *handler;
   175 		if (m_FreeMenuHandlers.empty())
   176 		{
   177 			handler = new CMenuHandler(pFunction, flags);
   178 		} else {
   179 			handler = m_FreeMenuHandlers.front();
   180 			m_FreeMenuHandlers.pop();
   181 			handler->m_pBasic = pFunction;
   182 			handler->m_Flags = flags;
   183 		}
   184 		return handler;
   185 	}
   186 
   187 	void FreeMenuHandler(CMenuHandler *handler)
   188 	{
   189 		m_FreeMenuHandlers.push(handler);
   190 	}
   191 
   192 private:
   193 	HandleType_t m_PanelType;
   194 	CStack<CPanelHandler *> m_FreePanelHandlers;
   195 	CStack<CMenuHandler *> m_FreeMenuHandlers;
   196 	CVector<CPanelHandler *> m_PanelHandlers;
   197 } g_MenuHelpers;
   198 
   199 /**
   200  * BASIC PANEL HANDLER WRAPPER
   201  */
   202 
   203 void CPanelHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
   204 {
   205 	if (m_pFunc)
   206 	{
   207 		m_pFunc->PushCell(BAD_HANDLE);
   208 		m_pFunc->PushCell(MenuAction_Cancel);
   209 		m_pFunc->PushCell(client);
   210 		m_pFunc->PushCell(reason);
   211 		m_pFunc->Execute(NULL);
   212 	}
   213 	g_MenuHelpers.FreePanelHandler(this);
   214 }
   215 
   216 void CPanelHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
   217 {
   218 	if (m_pFunc)
   219 	{
   220 		m_pFunc->PushCell(BAD_HANDLE);
   221 		m_pFunc->PushCell(MenuAction_Select);
   222 		m_pFunc->PushCell(client);
   223 		m_pFunc->PushCell(item);
   224 		m_pFunc->Execute(NULL);
   225 	}
   226 	g_MenuHelpers.FreePanelHandler(this);
   227 }
   228 
   229 /**
   230  * MENU HANDLER WRAPPER
   231  */
   232 CMenuHandler::CMenuHandler(IPluginFunction *pBasic, int flags) : 
   233 	m_pBasic(pBasic), m_Flags(flags)
   234 {
   235 	/* :TODO: We can probably cache the handle ahead of time */
   236 }
   237 
   238 void CMenuHandler::OnMenuStart(IBaseMenu *menu)
   239 {
   240 	if ((m_Flags & (int)MenuAction_Start) == (int)MenuAction_Start)
   241 	{
   242 		DoAction(menu, MenuAction_Start, 0, 0);
   243 	}
   244 }
   245 
   246 void CMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *panel)
   247 {
   248 	if ((m_Flags & (int)MenuAction_Display) == (int)MenuAction_Display)
   249 	{
   250 		HandleSecurity sec;
   251 		sec.pIdentity = m_pBasic->GetParentContext()->GetIdentity();
   252 		sec.pOwner = g_pCoreIdent;
   253 	
   254 		HandleAccess access;
   255 		g_HandleSys.InitAccessDefaults(NULL, &access);
   256 		access.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
   257 
   258 		Handle_t hndl =  g_HandleSys.CreateHandleEx(g_MenuHelpers.GetPanelType(), panel, &sec, &access, NULL);
   259 
   260 		DoAction(menu, MenuAction_Display, client, hndl);
   261 
   262 		g_HandleSys.FreeHandle(hndl, &sec);
   263 	}
   264 }
   265 
   266 void CMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
   267 {
   268 	DoAction(menu, MenuAction_Select, client, item);
   269 }
   270 
   271 void CMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
   272 {
   273 	DoAction(menu, MenuAction_Cancel, client, (cell_t)reason);
   274 }
   275 
   276 void CMenuHandler::OnMenuEnd(IBaseMenu *menu)
   277 {
   278 	DoAction(menu, MenuAction_End, 0, 0);
   279 }
   280 
   281 void CMenuHandler::OnMenuDestroy(IBaseMenu *menu)
   282 {
   283 	g_MenuHelpers.FreeMenuHandler(this);
   284 }
   285 
   286 void CMenuHandler::OnMenuVoteStart(IBaseMenu *menu)
   287 {
   288 	DoAction(menu, MenuAction_VoteStart, 0, 0);
   289 }
   290 
   291 void CMenuHandler::OnMenuVoteEnd(IBaseMenu *menu, unsigned int item)
   292 {
   293 	DoAction(menu, MenuAction_VoteEnd, item, 0);
   294 }
   295 
   296 void CMenuHandler::OnMenuVoteCancel(IBaseMenu *menu)
   297 {
   298 	DoAction(menu, MenuAction_VoteCancel, 0, 0);
   299 }
   300 
   301 void CMenuHandler::DoAction(IBaseMenu *menu, MenuAction action, cell_t param1, cell_t param2)
   302 {
   303 	m_pBasic->PushCell(menu->GetHandle());
   304 	m_pBasic->PushCell((cell_t)action);
   305 	m_pBasic->PushCell(param1);
   306 	m_pBasic->PushCell(param2);
   307 	m_pBasic->Execute(NULL);
   308 }
   309 
   310 /**
   311  * INLINE FUNCTIONS FOR NATIVES
   312  */
   313 
   314 inline Handle_t MakePanelHandle(IMenuPanel *panel, IPluginContext *pContext)
   315 {
   316 	return g_HandleSys.CreateHandle(g_MenuHelpers.GetPanelType(), panel, pContext->GetIdentity(), g_pCoreIdent, NULL);
   317 }
   318 
   319 inline HandleError ReadPanelHandle(Handle_t hndl, IMenuPanel **panel)
   320 {
   321 	HandleSecurity sec;
   322 	sec.pIdentity = g_pCoreIdent;
   323 	sec.pOwner = NULL;
   324 	return g_HandleSys.ReadHandle(hndl, g_MenuHelpers.GetPanelType(), &sec, (void **)panel);
   325 }
   326 
   327 inline IMenuStyle *GetStyleFromCell(cell_t cell)
   328 {
   329 	enum MenuStyle
   330 	{
   331 		MenuStyle_Default = 0,		/**< The "default" menu style for the mod */
   332 		MenuStyle_Valve = 1,		/**< The Valve provided menu style (Used on HL2DM) */
   333 		MenuStyle_Radio = 2,		/**< The simpler menu style commonly used on CS:S */
   334 	};
   335 
   336 	if (cell == MenuStyle_Valve)
   337 	{
   338 		return &g_ValveMenuStyle;
   339 	} else if (cell == MenuStyle_Radio
   340 			   && g_RadioMenuStyle.IsSupported())
   341 	{
   342 		return &g_RadioMenuStyle;
   343 	}
   344 
   345 	return g_Menus.GetDefaultStyle();
   346 }
   347 
   348 /***********************************
   349  **** NATIVE DEFINITIONS ***********
   350  ***********************************/
   351 
   352 static cell_t CreateMenu(IPluginContext *pContext, const cell_t *params)
   353 {
   354 	IMenuStyle *style = g_Menus.GetDefaultStyle();
   355 	IPluginFunction *pFunction;
   356 
   357 	if ((pFunction=pContext->GetFunctionById(params[1])) == NULL)
   358 	{
   359 		return pContext->ThrowNativeError("Function id %x is invalid", params[1]);
   360 	}
   361 
   362 	CMenuHandler *handler = g_MenuHelpers.GetMenuHandler(pFunction, params[2]);
   363 	IBaseMenu *menu = style->CreateMenu(handler, pContext->GetIdentity());
   364 
   365 	Handle_t hndl = menu->GetHandle();
   366 	if (!hndl)
   367 	{
   368 		menu->Destroy();
   369 		return BAD_HANDLE;
   370 	}
   371 
   372 	return hndl;
   373 }
   374 
   375 static cell_t DisplayMenu(IPluginContext *pContext, const cell_t *params)
   376 {
   377 	Handle_t hndl = (Handle_t)params[1];
   378 	HandleError err;
   379 	IBaseMenu *menu;
   380 
   381 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   382 	{
   383 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   384 	}
   385 
   386 	return menu->Display(params[2], params[3]) ? 1 : 0;
   387 }
   388 
   389 static cell_t VoteMenu(IPluginContext *pContext, const cell_t *params)
   390 {
   391 	Handle_t hndl = (Handle_t)params[1];
   392 	HandleError err;
   393 	IBaseMenu *menu;
   394 
   395 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   396 	{
   397 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   398 	}
   399 
   400 	cell_t *addr;
   401 	pContext->LocalToPhysAddr(params[2], &addr);
   402 
   403 	return menu->BroadcastVote(addr, params[3], params[4]) ? 1 : 0;
   404 }
   405 
   406 static cell_t AddMenuItem(IPluginContext *pContext, const cell_t *params)
   407 {
   408 	Handle_t hndl = (Handle_t)params[1];
   409 	HandleError err;
   410 	IBaseMenu *menu;
   411 
   412 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   413 	{
   414 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   415 	}
   416 
   417 	char *info;
   418 	ItemDrawInfo dr;
   419 
   420 	pContext->LocalToString(params[2], &info);
   421 	pContext->LocalToString(params[3], (char **)&dr.display);
   422 	dr.style = params[4];
   423 
   424 	return menu->AppendItem(info, dr) ? 1 : 0;
   425 }
   426 
   427 static cell_t InsertMenuItem(IPluginContext *pContext, const cell_t *params)
   428 {
   429 	Handle_t hndl = (Handle_t)params[1];
   430 	HandleError err;
   431 	IBaseMenu *menu;
   432 
   433 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   434 	{
   435 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   436 	}
   437 
   438 	char *info;
   439 	ItemDrawInfo dr;
   440 
   441 	pContext->LocalToString(params[3], &info);
   442 	pContext->LocalToString(params[4], (char **)&dr.display);
   443 	dr.style = params[5];
   444 
   445 	return menu->InsertItem(params[2], info, dr) ? 1 : 0;
   446 }
   447 
   448 static cell_t RemoveMenuItem(IPluginContext *pContext, const cell_t *params)
   449 {
   450 	Handle_t hndl = (Handle_t)params[1];
   451 	HandleError err;
   452 	IBaseMenu *menu;
   453 
   454 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   455 	{
   456 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   457 	}
   458 
   459 	return menu->RemoveItem(params[2]) ? 1 : 0;
   460 }
   461 
   462 static cell_t RemoveAllMenuItems(IPluginContext *pContext, const cell_t *params)
   463 {
   464 	Handle_t hndl = (Handle_t)params[1];
   465 	HandleError err;
   466 	IBaseMenu *menu;
   467 
   468 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   469 	{
   470 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   471 	}
   472 
   473 	menu->RemoveAllItems();
   474 
   475 	return 1;
   476 }
   477 
   478 static cell_t GetMenuItem(IPluginContext *pContext, const cell_t *params)
   479 {
   480 	Handle_t hndl = (Handle_t)params[1];
   481 	HandleError err;
   482 	IBaseMenu *menu;
   483 
   484 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   485 	{
   486 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   487 	}
   488 
   489 	ItemDrawInfo dr;
   490 	const char *info;
   491 
   492 	if ((info=menu->GetItemInfo(params[2], &dr)) == NULL)
   493 	{
   494 		return 0;
   495 	}
   496 
   497 	pContext->StringToLocalUTF8(params[3], params[4], info, NULL);
   498 	pContext->StringToLocalUTF8(params[6], params[7], dr.display ? dr.display : "", NULL);
   499 
   500 	cell_t *addr;
   501 	pContext->LocalToPhysAddr(params[5], &addr);
   502 	*addr = dr.style;
   503 
   504 	return 1;
   505 }
   506 
   507 static cell_t SetMenuPagination(IPluginContext *pContext, const cell_t *params)
   508 {
   509 	Handle_t hndl = (Handle_t)params[1];
   510 	HandleError err;
   511 	IBaseMenu *menu;
   512 
   513 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   514 	{
   515 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   516 	}
   517 
   518 	return menu->SetPagination(params[2]) ? 1 : 0;
   519 }
   520 
   521 static cell_t GetMenuPagination(IPluginContext *pContext, const cell_t *params)
   522 {
   523 	Handle_t hndl = (Handle_t)params[1];
   524 	HandleError err;
   525 	IBaseMenu *menu;
   526 
   527 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   528 	{
   529 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   530 	}
   531 
   532 	return menu->GetPagination();
   533 }
   534 
   535 static cell_t GetMenuItemCount(IPluginContext *pContext, const cell_t *params)
   536 {
   537 	Handle_t hndl = (Handle_t)params[1];
   538 	HandleError err;
   539 	IBaseMenu *menu;
   540 
   541 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   542 	{
   543 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   544 	}
   545 
   546 	return menu->GetItemCount();
   547 }
   548 
   549 static cell_t SetMenuTitle(IPluginContext *pContext, const cell_t *params)
   550 {
   551 	Handle_t hndl = (Handle_t)params[1];
   552 	HandleError err;
   553 	IBaseMenu *menu;
   554 
   555 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   556 	{
   557 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   558 	}
   559 
   560 	char buffer[1024];
   561 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   562 
   563 	menu->SetDefaultTitle(buffer);
   564 
   565 	return 1;
   566 }
   567 
   568 static cell_t CreatePanelFromMenu(IPluginContext *pContext, const cell_t *params)
   569 {
   570 	Handle_t hndl = (Handle_t)params[1];
   571 	HandleError err;
   572 	IBaseMenu *menu;
   573 
   574 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   575 	{
   576 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   577 	}
   578 
   579 	IMenuPanel *panel = menu->CreatePanel();
   580 	hndl = MakePanelHandle(panel, pContext);
   581 	if (!hndl)
   582 	{
   583 		panel->DeleteThis();
   584 	}
   585 
   586 	return hndl;
   587 }
   588 
   589 static cell_t GetMenuExitButton(IPluginContext *pContext, const cell_t *params)
   590 {
   591 	Handle_t hndl = (Handle_t)params[1];
   592 	HandleError err;
   593 	IBaseMenu *menu;
   594 
   595 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   596 	{
   597 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   598 	}
   599 
   600 	return menu->GetExitButton() ? 1 : 0;
   601 }
   602 
   603 static cell_t SetMenuExitButton(IPluginContext *pContext, const cell_t *params)
   604 {
   605 	Handle_t hndl = (Handle_t)params[1];
   606 	HandleError err;
   607 	IBaseMenu *menu;
   608 
   609 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   610 	{
   611 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   612 	}
   613 
   614 	return menu->SetExitButton(params[2] ? true : false) ? 1 : 0;
   615 }
   616 
   617 static cell_t CancelMenu(IPluginContext *pContext, const cell_t *params)
   618 {
   619 	Handle_t hndl = (Handle_t)params[1];
   620 	HandleError err;
   621 	IBaseMenu *menu;
   622 
   623 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   624 	{
   625 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   626 	}
   627 
   628 	menu->Cancel();
   629 
   630 	return 1;
   631 }
   632 
   633 static cell_t IsVoteInProgress(IPluginContext *pContext, const cell_t *params)
   634 {
   635 	Handle_t hndl = (Handle_t)params[1];
   636 	HandleError err;
   637 	IBaseMenu *menu;
   638 
   639 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   640 	{
   641 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   642 	}
   643 
   644 	return menu->IsVoteInProgress() ? 1 : 0;
   645 }
   646 
   647 static cell_t GetMenuStyle(IPluginContext *pContext, const cell_t *params)
   648 {
   649 	Handle_t hndl = (Handle_t)params[1];
   650 	HandleError err;
   651 	IBaseMenu *menu;
   652 
   653 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   654 	{
   655 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   656 	}
   657 
   658 	return menu->GetDrawStyle()->GetHandle();
   659 }
   660 
   661 static cell_t GetMenuStyleHandle(IPluginContext *pContext, const cell_t *params)
   662 {
   663 	IMenuStyle *style = GetStyleFromCell(params[1]);
   664 	if (!style)
   665 	{
   666 		return BAD_HANDLE;
   667 	}
   668 
   669 	return style->GetHandle();
   670 }
   671 
   672 static cell_t CreatePanel(IPluginContext *pContext, const cell_t *params)
   673 {
   674 	Handle_t hndl = (Handle_t)params[1];
   675 	HandleError err;
   676 	IMenuStyle *style;
   677 
   678 	if (hndl != 0)
   679 	{
   680 		if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
   681 		{
   682 			return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
   683 		}
   684 	} else {
   685 		style = g_Menus.GetDefaultStyle();
   686 	}
   687 
   688 	IMenuPanel *panel = style->CreatePanel();
   689 
   690 	hndl = MakePanelHandle(panel, pContext);
   691 	if (!hndl)
   692 	{
   693 		panel->DeleteThis();
   694 		return BAD_HANDLE;
   695 	}
   696 
   697 	return hndl;
   698 }
   699 
   700 static cell_t CreateMenuEx(IPluginContext *pContext, const cell_t *params)
   701 {
   702 	Handle_t hndl = (Handle_t)params[1];
   703 	HandleError err;
   704 	IMenuStyle *style;
   705 
   706 	if (hndl != 0)
   707 	{
   708 		if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
   709 		{
   710 			return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
   711 		}
   712 	} else {
   713 		style = g_Menus.GetDefaultStyle();
   714 	}
   715 
   716 	IPluginFunction *pFunction;
   717 	if ((pFunction=pContext->GetFunctionById(params[2])) == NULL)
   718 	{
   719 		return pContext->ThrowNativeError("Function id %x is invalid", params[2]);
   720 	}
   721 
   722 	CMenuHandler *handler = g_MenuHelpers.GetMenuHandler(pFunction, params[3]);
   723 
   724 	IBaseMenu *pMenu = style->CreateMenu(handler, pContext->GetIdentity());
   725 	hndl = pMenu->GetHandle();
   726 	if (!hndl)
   727 	{
   728 		pMenu->Destroy();
   729 		return BAD_HANDLE;
   730 	}
   731 
   732 	return hndl;
   733 }
   734 
   735 static cell_t GetClientMenu(IPluginContext *pContext, const cell_t *params)
   736 {
   737 	Handle_t hndl = (Handle_t)params[2];
   738 	HandleError err;
   739 	IMenuStyle *style;
   740 
   741 	if (hndl != 0)
   742 	{
   743 		if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
   744 		{
   745 			return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
   746 		}
   747 	} else {
   748 		style = g_Menus.GetDefaultStyle();
   749 	}
   750 
   751 	return style->GetClientMenu(params[1], NULL);
   752 }
   753 
   754 static cell_t CancelClientMenu(IPluginContext *pContext, const cell_t *params)
   755 {
   756 	Handle_t hndl = (Handle_t)params[3];
   757 	HandleError err;
   758 	IMenuStyle *style;
   759 
   760 	if (hndl != 0)
   761 	{
   762 		if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
   763 		{
   764 			return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
   765 		}
   766 	} else {
   767 		style = g_Menus.GetDefaultStyle();
   768 	}
   769 
   770 	return style->CancelClientMenu(params[1], params[2] ? true : false) ? 1 : 0;
   771 }
   772 
   773 static cell_t GetMaxPageItems(IPluginContext *pContext, const cell_t *params)
   774 {
   775 	Handle_t hndl = (Handle_t)params[1];
   776 	HandleError err;
   777 	IMenuStyle *style;
   778 
   779 	if (hndl != 0)
   780 	{
   781 		if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
   782 		{
   783 			return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
   784 		}
   785 	} else {
   786 		style = g_Menus.GetDefaultStyle();
   787 	}
   788 
   789 	return style->GetMaxPageItems();
   790 }
   791 
   792 static cell_t GetPanelStyle(IPluginContext *pContext, const cell_t *params)
   793 {
   794 	Handle_t hndl = (Handle_t)params[1];
   795 	HandleError err;
   796 	IMenuPanel *panel;
   797 
   798 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   799 	{
   800 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   801 	}
   802 
   803 	return panel->GetParentStyle()->GetHandle();
   804 }
   805 
   806 static cell_t SetPanelTitle(IPluginContext *pContext, const cell_t *params)
   807 {
   808 	Handle_t hndl = (Handle_t)params[1];
   809 	HandleError err;
   810 	IMenuPanel *panel;
   811 
   812 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   813 	{
   814 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   815 	}
   816 
   817 	char *text;
   818 	pContext->LocalToString(params[2], &text);
   819 
   820 	panel->DrawTitle(text, params[3] ? true : false);
   821 
   822 	return 1;
   823 }
   824 
   825 static cell_t DrawPanelItem(IPluginContext *pContext, const cell_t *params)
   826 {
   827 	Handle_t hndl = (Handle_t)params[1];
   828 	HandleError err;
   829 	IMenuPanel *panel;
   830 
   831 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   832 	{
   833 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   834 	}
   835 
   836 	ItemDrawInfo dr;
   837 	pContext->LocalToString(params[2], (char **)&dr.display);
   838 	dr.style = params[3];
   839 
   840 	return panel->DrawItem(dr);
   841 }
   842 
   843 static cell_t DrawPanelText(IPluginContext *pContext, const cell_t *params)
   844 {
   845 	Handle_t hndl = (Handle_t)params[1];
   846 	HandleError err;
   847 	IMenuPanel *panel;
   848 
   849 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   850 	{
   851 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   852 	}
   853 
   854 	char *text;
   855 	pContext->LocalToString(params[2], &text);
   856 
   857 	return panel->DrawRawLine(text) ? 1 : 0;
   858 }
   859 
   860 static cell_t CanPanelDrawFlags(IPluginContext *pContext, const cell_t *params)
   861 {
   862 	Handle_t hndl = (Handle_t)params[1];
   863 	HandleError err;
   864 	IMenuPanel *panel;
   865 
   866 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   867 	{
   868 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   869 	}
   870 
   871 	return panel->CanDrawItem(params[2]);
   872 }
   873 
   874 static cell_t SendPanelToClient(IPluginContext *pContext, const cell_t *params)
   875 {
   876 	Handle_t hndl = (Handle_t)params[1];
   877 	HandleError err;
   878 	IMenuPanel *panel;
   879 
   880 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   881 	{
   882 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   883 	}
   884 
   885 	IPluginFunction *pFunction;
   886 	if ((pFunction=pContext->GetFunctionById(params[3])) == NULL)
   887 	{
   888 		return pContext->ThrowNativeError("Function id %x is invalid", params[3]);
   889 	}
   890 
   891 	CPanelHandler *handler = g_MenuHelpers.GetPanelHandler(pFunction);
   892 	if (!panel->SendDisplay(params[2], handler, params[4]))
   893 	{
   894 		g_MenuHelpers.FreePanelHandler(handler);
   895 	}
   896 
   897 	return 1;
   898 }
   899 
   900 static cell_t SetPanelKeys(IPluginContext *pContext, const cell_t *params)
   901 {
   902 	Handle_t hndl = (Handle_t)params[1];
   903 	HandleError err;
   904 	IMenuPanel *panel;
   905 
   906 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   907 	{
   908 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   909 	}
   910 
   911 	return panel->SetSelectableKeys(params[2]);
   912 }
   913 
   914 static cell_t GetPanelCurrentKey(IPluginContext *pContext, const cell_t *params)
   915 {
   916 	Handle_t hndl = (Handle_t)params[1];
   917 	HandleError err;
   918 	IMenuPanel *panel;
   919 
   920 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   921 	{
   922 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   923 	}
   924 
   925 	return panel->GetCurrentKey();
   926 }
   927 
   928 static cell_t SetPanelCurrentKey(IPluginContext *pContext, const cell_t *params)
   929 {
   930 	Handle_t hndl = (Handle_t)params[1];
   931 	HandleError err;
   932 	IMenuPanel *panel;
   933 
   934 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   935 	{
   936 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   937 	}
   938 
   939 	return panel->SetCurrentKey(params[2]) ? 1 : 0;
   940 }
   941 
   942 REGISTER_NATIVES(menuNatives)
   943 {
   944 	{"AddMenuItem",				AddMenuItem},
   945 	{"CanPanelDrawFlags",		CanPanelDrawFlags},
   946 	{"CancelClientMenu",		CancelClientMenu},
   947 	{"CancelMenu",				CancelMenu},
   948 	{"CreateMenu",				CreateMenu},
   949 	{"CreateMenuEx",			CreateMenuEx},
   950 	{"CreatePanel",				CreatePanel},
   951 	{"CreatePanelFromMenu",		CreatePanelFromMenu},
   952 	{"DisplayMenu",				DisplayMenu},
   953 	{"DrawPanelItem",			DrawPanelItem},
   954 	{"DrawPanelText",			DrawPanelText},
   955 	{"GetClientMenu",			GetClientMenu},
   956 	{"GetMaxPageItems",			GetMaxPageItems},
   957 	{"GetMenuExitButton",		GetMenuExitButton},
   958 	{"GetMenuItem",				GetMenuItem},
   959 	{"GetMenuItemCount",		GetMenuItemCount},
   960 	{"GetMenuPagination",		GetMenuPagination},
   961 	{"GetMenuStyle",			GetMenuStyle},
   962 	{"GetMenuStyleHandle",		GetMenuStyleHandle},
   963 	{"GetPanelCurrentKey",		GetPanelCurrentKey},
   964 	{"GetPanelStyle",			GetPanelStyle},
   965 	{"InsertMenuItem",			InsertMenuItem},
   966 	{"IsVoteInProgress",		IsVoteInProgress},
   967 	{"RemoveAllMenuItems",		RemoveAllMenuItems},
   968 	{"RemoveMenuItem",			RemoveMenuItem},
   969 	{"SendPanelToClient",		SendPanelToClient},
   970 	{"SetMenuExitButton",		SetMenuExitButton},
   971 	{"SetMenuPagination",		SetMenuPagination},
   972 	{"SetMenuTitle",			SetMenuTitle},
   973 	{"SetPanelCurrentKey",		SetPanelCurrentKey},
   974 	{"SetPanelTitle",			SetPanelTitle},
   975 	{"SetPanelKeys",			SetPanelKeys},
   976 	{"VoteMenu",				VoteMenu},
   977 	{NULL,						NULL},
   978 };