dvander@790: /**
dvander@790: * vim: set ts=4 :
ds@1330: * =============================================================================
dvander@1231: * SourceMod
ds@1947: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
ds@1330: * =============================================================================
dvander@790: *
ds@1330: * This program is free software; you can redistribute it and/or modify it under
ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330: * Free Software Foundation.
dvander@1231: *
ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
ds@1330: * details.
dvander@1231: *
ds@1330: * You should have received a copy of the GNU General Public License along with
ds@1330: * this program. If not, see .
dvander@1231: *
ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in
ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants
ds@1330: * this exception to all derivative works. AlliedModders LLC defines further
ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330: * or .
dvander@790: *
dvander@790: * Version: $Id$
dvander@790: */
dvander@790:
dvander@790: #include "sm_globals.h"
dvander@790: #include
dvander@1269: #include "DebugReporter.h"
dvander@790: #include "MenuManager.h"
dvander@790: #include "MenuStyle_Valve.h"
dvander@790: #include "MenuStyle_Radio.h"
dvander@790: #include "HandleSys.h"
dvander@790: #include "PluginSys.h"
dvander@1705: #include "PlayerManager.h"
dvander@1011: #include "sm_stringutil.h"
dvander@1291: #include "sourcemm_api.h"
dvander@970: #if defined MENU_DEBUG
dvander@970: #include "Logger.h"
dvander@970: #endif
dvander@1522: #include "ChatTriggers.h"
dvander@790:
dvander@790: #if defined CreateMenu
dvander@790: #undef CreateMenu
dvander@790: #endif
dvander@790:
dvander@790: /**
dvander@790: * And God said, "let there be menus," and behold, there were menus.
dvander@790: * God saw the menus and they were good. And the evening and the morning
dvander@790: * were the third day.
dvander@790: */
dvander@790:
dvander@790: enum MenuAction
dvander@790: {
dvander@790: MenuAction_Start = (1<<0), /**< A menu has been started (nothing passed) */
dvander@790: MenuAction_Display = (1<<1), /**< A menu is about to be displayed (param1=client, param2=MenuPanel Handle) */
dvander@790: MenuAction_Select = (1<<2), /**< An item was selected (param1=client, param2=item) */
dvander@790: MenuAction_Cancel = (1<<3), /**< The menu was cancelled (param1=client, param2=item) */
dvander@790: MenuAction_End = (1<<4), /**< A menu's display/selection cycle is complete (nothing passed). */
dvander@790: MenuAction_VoteEnd = (1<<5), /**< (VOTE ONLY): A vote sequence has ended (param1=chosen item) */
dvander@878: MenuAction_VoteStart = (1<<6), /**< (VOTE ONLY): A vote sequence has started */
dvander@885: MenuAction_VoteCancel = (1<<7), /**< (VOTE ONLY): A vote sequence has been cancelled (nothing passed) */
dvander@1006: MenuAction_DrawItem = (1<<8), /**< A style is being drawn; return the new style (param1=client, param2=item) */
dvander@1163: MenuAction_DisplayItem = (1<<9), /**< the odd duck */
dvander@790: };
dvander@790:
dvander@790: class CPanelHandler : public IMenuHandler
dvander@790: {
dvander@790: friend class MenuNativeHelpers;
dvander@790: public:
dvander@790: CPanelHandler()
dvander@790: {
dvander@790: }
dvander@790: void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
dvander@790: void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item);
dvander@790: private:
dvander@790: IPluginFunction *m_pFunc;
dvander@790: IPlugin *m_pPlugin;
dvander@790: };
dvander@790:
dvander@790: class CMenuHandler : public IMenuHandler
dvander@790: {
dvander@790: friend class MenuNativeHelpers;
dvander@790: public:
dvander@790: CMenuHandler(IPluginFunction *pBasic, int flags);
dvander@790: public:
dvander@790: void OnMenuStart(IBaseMenu *menu);
dvander@790: void OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display);
dvander@1476: void OnMenuSelect2(IBaseMenu *menu, int client, unsigned int item, unsigned int item_on_page);
dvander@790: void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
dvander@997: void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason);
dvander@790: void OnMenuDestroy(IBaseMenu *menu);
dvander@878: void OnMenuVoteStart(IBaseMenu *menu);
dvander@1269: void OnMenuVoteResults(IBaseMenu *menu, const menu_vote_result_t *results);
dvander@1296: void OnMenuVoteCancel(IBaseMenu *menu, VoteCancelReason reason);
dvander@1006: void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
dvander@1163: unsigned int OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr);
dvander@1269: bool OnSetHandlerOption(const char *option, const void *data);
dvander@790: #if 0
dvander@790: void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
dvander@790: void OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display);
dvander@790: #endif
dvander@790: private:
dvander@1006: cell_t DoAction(IBaseMenu *menu, MenuAction action, cell_t param1, cell_t param2, cell_t def_res=0);
dvander@878: private:
dvander@790: IPluginFunction *m_pBasic;
dvander@790: int m_Flags;
dvander@1269: IPluginFunction *m_pVoteResults;
dvander@1269: cell_t m_fnVoteResult;
dvander@790: };
dvander@790:
dvander@790: /**
dvander@790: * GLOBAL CLASS FOR HELPERS
dvander@790: */
dvander@790:
dvander@790: class MenuNativeHelpers :
dvander@790: public SMGlobalClass,
dvander@790: public IHandleTypeDispatch,
dvander@790: public IPluginsListener
dvander@790: {
dvander@790: public:
dvander@790: virtual void OnSourceModAllInitialized()
dvander@790: {
dvander@790: m_PanelType = g_HandleSys.CreateType("IMenuPanel", this, 0, NULL, NULL, g_pCoreIdent, NULL);
dvander@1163: m_TempPanelType = g_HandleSys.CreateType("TempIMenuPanel", this, m_PanelType, NULL, NULL, g_pCoreIdent, NULL);
dvander@790: g_PluginSys.AddPluginsListener(this);
dvander@790: }
dvander@790:
dvander@790: virtual void OnSourceModShutdown()
dvander@790: {
dvander@1163: g_HandleSys.RemoveType(m_TempPanelType, g_pCoreIdent);
dvander@790: g_HandleSys.RemoveType(m_PanelType, g_pCoreIdent);
dvander@790:
dvander@790: while (!m_FreePanelHandlers.empty())
dvander@790: {
dvander@790: delete m_FreePanelHandlers.front();
dvander@790: m_FreePanelHandlers.pop();
dvander@790: }
dvander@790:
dvander@790: while (!m_FreeMenuHandlers.empty())
dvander@790: {
dvander@790: delete m_FreeMenuHandlers.front();
dvander@790: m_FreeMenuHandlers.pop();
dvander@790: }
dvander@790: }
dvander@790:
dvander@790: virtual void OnHandleDestroy(HandleType_t type, void *object)
dvander@790: {
dvander@1163: if (type == m_TempPanelType)
dvander@1163: {
dvander@1163: return;
dvander@1163: }
dvander@1163:
dvander@790: IMenuPanel *panel = (IMenuPanel *)object;
dvander@790: panel->DeleteThis();
dvander@790: }
dvander@790:
dvander@1766: virtual bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
dvander@1766: {
dvander@1766: *pSize = ((IMenuPanel *)object)->GetApproxMemUsage();
dvander@1766: return true;
dvander@1766: }
dvander@1766:
dvander@790: /**
dvander@1269: * It is extremely important that unloaded plugins don't crash.
dvander@790: * Thus, if a plugin unloads, we run through every handler we have.
dvander@790: * This means we do almost no runtime work for keeping track of
dvander@790: * our panel handlers (we don't have to store a list of the running
dvander@790: * ones), but when push comes to shove, we have to scan them all
dvander@790: * in case any of them are active.
dvander@790: */
dvander@790: virtual void OnPluginUnloaded(IPlugin *plugin)
dvander@790: {
dvander@790: for (size_t i = 0; i < m_PanelHandlers.size(); i++)
dvander@790: {
dvander@790: if (m_PanelHandlers[i]->m_pPlugin == plugin)
dvander@790: {
dvander@790: m_PanelHandlers[i]->m_pPlugin = NULL;
dvander@790: m_PanelHandlers[i]->m_pFunc = NULL;
dvander@790: }
dvander@790: }
dvander@790: }
dvander@790:
dvander@790: inline HandleType_t GetPanelType()
dvander@790: {
dvander@790: return m_PanelType;
dvander@790: }
dvander@790:
dvander@1163: inline HandleType_t GetTempPanelType()
dvander@1163: {
dvander@1163: return m_TempPanelType;
dvander@1163: }
dvander@1163:
dvander@790: CPanelHandler *GetPanelHandler(IPluginFunction *pFunction)
dvander@790: {
dvander@790: CPanelHandler *handler;
dvander@790: if (m_FreePanelHandlers.empty())
dvander@790: {
dvander@790: handler = new CPanelHandler;
dvander@790: m_PanelHandlers.push_back(handler);
dvander@790: } else {
dvander@790: handler = m_FreePanelHandlers.front();
dvander@790: m_FreePanelHandlers.pop();
dvander@790: }
dvander@790: handler->m_pFunc = pFunction;
dvander@790: handler->m_pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
dvander@790: return handler;
dvander@790: }
dvander@790:
dvander@790: void FreePanelHandler(CPanelHandler *handler)
dvander@790: {
dvander@790: handler->m_pFunc = NULL;
dvander@790: handler->m_pPlugin = NULL;
dvander@790: m_FreePanelHandlers.push(handler);
dvander@790: }
dvander@790:
dvander@790: CMenuHandler *GetMenuHandler(IPluginFunction *pFunction, int flags)
dvander@790: {
dvander@790: CMenuHandler *handler;
dvander@790: if (m_FreeMenuHandlers.empty())
dvander@790: {
dvander@790: handler = new CMenuHandler(pFunction, flags);
dvander@790: } else {
dvander@790: handler = m_FreeMenuHandlers.front();
dvander@790: m_FreeMenuHandlers.pop();
dvander@790: handler->m_pBasic = pFunction;
dvander@790: handler->m_Flags = flags;
dvander@1269: handler->m_pVoteResults = NULL;
dvander@790: }
dvander@790: return handler;
dvander@790: }
dvander@790:
dvander@790: void FreeMenuHandler(CMenuHandler *handler)
dvander@790: {
dvander@790: m_FreeMenuHandlers.push(handler);
dvander@790: }
dvander@790:
dvander@790: private:
dvander@790: HandleType_t m_PanelType;
dvander@1163: HandleType_t m_TempPanelType;
dvander@790: CStack m_FreePanelHandlers;
dvander@790: CStack m_FreeMenuHandlers;
dvander@790: CVector m_PanelHandlers;
dvander@790: } g_MenuHelpers;
dvander@790:
dvander@790: /**
dvander@790: * BASIC PANEL HANDLER WRAPPER
dvander@790: */
dvander@790:
dvander@790: void CPanelHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
dvander@790: {
dvander@790: if (m_pFunc)
dvander@790: {
dvander@790: m_pFunc->PushCell(BAD_HANDLE);
dvander@790: m_pFunc->PushCell(MenuAction_Cancel);
dvander@790: m_pFunc->PushCell(client);
dvander@790: m_pFunc->PushCell(reason);
dvander@790: m_pFunc->Execute(NULL);
dvander@790: }
dvander@790: g_MenuHelpers.FreePanelHandler(this);
dvander@790: }
dvander@790:
dvander@790: void CPanelHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
dvander@790: {
dvander@790: if (m_pFunc)
dvander@790: {
dvander@1522: unsigned int old_reply = g_ChatTriggers.SetReplyTo(SM_REPLY_CHAT);
dvander@790: m_pFunc->PushCell(BAD_HANDLE);
dvander@790: m_pFunc->PushCell(MenuAction_Select);
dvander@790: m_pFunc->PushCell(client);
dvander@790: m_pFunc->PushCell(item);
dvander@790: m_pFunc->Execute(NULL);
dvander@1522: g_ChatTriggers.SetReplyTo(old_reply);
dvander@790: }
dvander@790: g_MenuHelpers.FreePanelHandler(this);
dvander@790: }
dvander@790:
dvander@1163: static IMenuPanel *s_pCurPanel = NULL;
dvander@1163: static unsigned int s_CurPanelReturn = 0;
dvander@1163: static const ItemDrawInfo *s_CurDrawInfo = NULL;
dvander@1476: static unsigned int *s_CurSelectPosition = NULL;
dvander@1163:
dvander@790: /**
dvander@790: * MENU HANDLER WRAPPER
dvander@790: */
dvander@790: CMenuHandler::CMenuHandler(IPluginFunction *pBasic, int flags) :
dvander@1269: m_pBasic(pBasic), m_Flags(flags), m_pVoteResults(NULL)
dvander@790: {
dvander@790: /* :TODO: We can probably cache the handle ahead of time */
dvander@790: }
dvander@790:
dvander@790: void CMenuHandler::OnMenuStart(IBaseMenu *menu)
dvander@790: {
dvander@790: if ((m_Flags & (int)MenuAction_Start) == (int)MenuAction_Start)
dvander@790: {
dvander@878: DoAction(menu, MenuAction_Start, 0, 0);
dvander@790: }
dvander@790: }
dvander@790:
dvander@790: void CMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *panel)
dvander@790: {
dvander@790: if ((m_Flags & (int)MenuAction_Display) == (int)MenuAction_Display)
dvander@790: {
dvander@790: HandleSecurity sec;
dvander@1163: sec.pIdentity = g_pCoreIdent;
dvander@1163: sec.pOwner = m_pBasic->GetParentContext()->GetIdentity();
dvander@790:
dvander@790: HandleAccess access;
dvander@790: g_HandleSys.InitAccessDefaults(NULL, &access);
dvander@790: access.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
dvander@790:
dvander@1163: Handle_t hndl = g_HandleSys.CreateHandleEx(g_MenuHelpers.GetTempPanelType(), panel, &sec, &access, NULL);
dvander@790:
dvander@878: DoAction(menu, MenuAction_Display, client, hndl);
dvander@790:
dvander@790: g_HandleSys.FreeHandle(hndl, &sec);
dvander@790: }
dvander@790: }
dvander@790:
dvander@1476: void CMenuHandler::OnMenuSelect2(IBaseMenu *menu, int client, unsigned int item, unsigned int item_on_page)
dvander@790: {
dvander@1476: /* Save old position first. */
dvander@1476: unsigned int first_item = item_on_page;
dvander@1476: unsigned int *old_pos = s_CurSelectPosition;
dvander@1476:
dvander@1476: s_CurSelectPosition = &first_item;
dvander@1476:
dvander@1522: unsigned int old_reply = g_ChatTriggers.SetReplyTo(SM_REPLY_CHAT);
dvander@878: DoAction(menu, MenuAction_Select, client, item);
dvander@1522: g_ChatTriggers.SetReplyTo(old_reply);
dvander@1476:
dvander@1476: s_CurSelectPosition = old_pos;
dvander@790: }
dvander@790:
dvander@790: void CMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
dvander@790: {
dvander@1522: unsigned int old_reply = g_ChatTriggers.SetReplyTo(SM_REPLY_CHAT);
dvander@878: DoAction(menu, MenuAction_Cancel, client, (cell_t)reason);
dvander@1522: g_ChatTriggers.SetReplyTo(old_reply);
dvander@790: }
dvander@790:
dvander@997: void CMenuHandler::OnMenuEnd(IBaseMenu *menu, MenuEndReason reason)
dvander@790: {
dvander@997: DoAction(menu, MenuAction_End, reason, 0);
dvander@790: }
dvander@790:
dvander@790: void CMenuHandler::OnMenuDestroy(IBaseMenu *menu)
dvander@790: {
dvander@790: g_MenuHelpers.FreeMenuHandler(this);
dvander@790: }
dvander@790:
dvander@878: void CMenuHandler::OnMenuVoteStart(IBaseMenu *menu)
dvander@878: {
dvander@878: DoAction(menu, MenuAction_VoteStart, 0, 0);
dvander@878: }
dvander@878:
dvander@1296: void CMenuHandler::OnMenuVoteCancel(IBaseMenu *menu, VoteCancelReason reason)
dvander@885: {
dvander@1296: DoAction(menu, MenuAction_VoteCancel, reason, 0);
dvander@885: }
dvander@885:
dvander@1006: void CMenuHandler::OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style)
dvander@1006: {
dvander@1006: if ((m_Flags & (int)MenuAction_DrawItem) == (int)MenuAction_DrawItem)
dvander@1006: {
dvander@1006: cell_t result = DoAction(menu, MenuAction_DrawItem, client, item, style);
dvander@1006: style = (unsigned int)result;
dvander@1006: }
dvander@1006: }
dvander@1006:
dvander@1163: unsigned int CMenuHandler::OnMenuDisplayItem(IBaseMenu *menu,
dvander@1163: int client,
dvander@1163: IMenuPanel *panel,
dvander@1163: unsigned int item,
dvander@1163: const ItemDrawInfo &dr)
dvander@1163: {
dvander@1163: if ((m_Flags & (int)MenuAction_DisplayItem) == (int)MenuAction_DisplayItem)
dvander@1163: {
dvander@1163: IMenuPanel *oldpanel = s_pCurPanel;
dvander@1163: unsigned int oldret = s_CurPanelReturn;
dvander@1163: const ItemDrawInfo *oldinfo = s_CurDrawInfo;
dvander@1163: s_pCurPanel = panel;
dvander@1163: s_CurPanelReturn = 0;
dvander@1163: s_CurDrawInfo = &dr;
dvander@1163:
dvander@1163: cell_t res = DoAction(menu, MenuAction_DisplayItem, client, item, 0);
dvander@1163:
dvander@1163: if (!res)
dvander@1163: {
dvander@1163: res = s_CurPanelReturn;
dvander@1163: }
dvander@1163:
dvander@1163: s_pCurPanel = oldpanel;
dvander@1163: s_CurPanelReturn = oldret;
dvander@1163: s_CurDrawInfo = oldinfo;
dvander@1163:
dvander@1163: return res;
dvander@1163: }
dvander@1163:
dvander@1163: return 0;
dvander@1163: }
dvander@1163:
dvander@1006: cell_t CMenuHandler::DoAction(IBaseMenu *menu, MenuAction action, cell_t param1, cell_t param2, cell_t def_res)
dvander@878: {
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] CMenuHandler::DoAction() (menu %p/%08x) (action %d) (param1 %d) (param2 %d)",
dvander@970: menu,
dvander@970: menu->GetHandle(),
dvander@970: action,
dvander@970: param1,
dvander@970: param2);
dvander@970: #endif
dvander@1006: cell_t res = def_res;
dvander@878: m_pBasic->PushCell(menu->GetHandle());
dvander@878: m_pBasic->PushCell((cell_t)action);
dvander@878: m_pBasic->PushCell(param1);
dvander@878: m_pBasic->PushCell(param2);
dvander@1006: m_pBasic->Execute(&res);
dvander@1006: return res;
dvander@878: }
dvander@878:
dvander@1269: void CMenuHandler::OnMenuVoteResults(IBaseMenu *menu, const menu_vote_result_t *results)
dvander@1269: {
dvander@1269: if (!m_pVoteResults)
dvander@1269: {
dvander@1269: /* Call MenuAction_VoteEnd instead. See if there are any extra winners. */
dvander@1269: unsigned int num_items = 1;
dvander@1269: for (unsigned int i=1; inum_items; i++)
dvander@1269: {
dvander@1269: if (results->item_list[i].count != results->item_list[0].count)
dvander@1269: {
dvander@1269: break;
dvander@1269: }
dvander@1269: num_items++;
dvander@1269: }
dvander@1269:
dvander@1269: /* See if we need to pick a random winner. */
dvander@1269: unsigned int winning_item;
dvander@1269: if (num_items > 1)
dvander@1269: {
dvander@1269: /* Yes, we do. */
dvander@1269: srand(time(NULL));
dvander@1269: winning_item = rand() % num_items;
dvander@1269: winning_item = results->item_list[winning_item].item;
dvander@1269: } else {
dvander@1269: /* No, take the first. */
dvander@1269: winning_item = results->item_list[0].item;
dvander@1269: }
dvander@1269:
dvander@1269: unsigned int total_votes = results->num_votes;
dvander@1269: unsigned int winning_votes = results->item_list[0].count;
dvander@1269:
dvander@1269: DoAction(menu, MenuAction_VoteEnd, winning_item, (total_votes << 16) | (winning_votes & 0xFFFF));
dvander@1269: } else {
dvander@1269: IPluginContext *pContext = m_pVoteResults->GetParentContext();
dvander@1269: bool no_call = false;
dvander@1269: int err;
dvander@1269:
dvander@1269: /* First array */
dvander@1269: cell_t client_array_address = -1;
dvander@1269: cell_t *client_array_base = NULL;
dvander@1269: cell_t client_array_size = results->num_clients + (results->num_clients * 2);
dvander@1269: if (client_array_size)
dvander@1269: {
dvander@1269: if ((err = pContext->HeapAlloc(client_array_size, &client_array_address, &client_array_base))
dvander@1269: != SP_ERROR_NONE)
dvander@1269: {
dvander@1269: g_DbgReporter.GenerateError(pContext, m_fnVoteResult, err, "Menu callback could not allocate %d bytes for client list.", client_array_size * sizeof(cell_t));
dvander@1269: no_call = true;
dvander@1269: } else {
dvander@1269: cell_t target_offs = sizeof(cell_t) * results->num_clients;
dvander@1269: cell_t *cur_index = client_array_base;
dvander@1269: cell_t *cur_array;
dvander@1269: for (unsigned int i=0; inum_clients; i++)
dvander@1269: {
dvander@1269: /* Copy the array index */
dvander@1269: *cur_index = target_offs;
dvander@1269: /* Get the current array address */
dvander@1269: cur_array = (cell_t *)((char *)cur_index + target_offs);
dvander@1269: /* Store information */
dvander@1269: cur_array[0] = results->client_list[i].client;
dvander@1269: cur_array[1] = results->client_list[i].item;
dvander@1269: /* Adjust for the new target by subtracting one indirection
dvander@1269: * and adding one array.
dvander@1269: */
dvander@1269: target_offs += (sizeof(cell_t) * 2) - sizeof(cell_t);
dvander@1269: cur_index++;
dvander@1269: }
dvander@1269: }
dvander@1269: }
dvander@1269:
dvander@1269: /* Second array */
dvander@1269: cell_t item_array_address = -1;
dvander@1269: cell_t *item_array_base = NULL;
dvander@1269: cell_t item_array_size = results->num_items + (results->num_items * 2);
dvander@1269: if (item_array_size)
dvander@1269: {
dvander@1269: if ((err = pContext->HeapAlloc(item_array_size, &item_array_address, &item_array_base))
dvander@1269: != SP_ERROR_NONE)
dvander@1269: {
dvander@1269: g_DbgReporter.GenerateError(pContext, m_fnVoteResult, err, "Menu callback could not allocate %d bytes for item list.", item_array_size);
dvander@1269: no_call = true;
dvander@1269: } else {
dvander@1269: cell_t target_offs = sizeof(cell_t) * results->num_items;
dvander@1269: cell_t *cur_index = item_array_base;
dvander@1269: cell_t *cur_array;
dvander@1269: for (unsigned int i=0; inum_items; i++)
dvander@1269: {
dvander@1269: /* Copy the array index */
dvander@1269: *cur_index = target_offs;
dvander@1269: /* Get the current array address */
dvander@1269: cur_array = (cell_t *)((char *)cur_index + target_offs);
dvander@1269: /* Store information */
dvander@1269: cur_array[0] = results->item_list[i].item;
dvander@1269: cur_array[1] = results->item_list[i].count;
dvander@1269: /* Adjust for the new target by subtracting one indirection
dvander@1269: * and adding one array.
dvander@1269: */
dvander@1269: target_offs += (sizeof(cell_t) * 2) - sizeof(cell_t);
dvander@1269: cur_index++;
dvander@1269: }
dvander@1269: }
dvander@1269: }
dvander@1269:
dvander@1269: /* Finally, push everything */
dvander@1269: if (!no_call)
dvander@1269: {
dvander@1271: m_pVoteResults->PushCell(menu->GetHandle());
dvander@1269: m_pVoteResults->PushCell(results->num_votes);
dvander@1269: m_pVoteResults->PushCell(results->num_clients);
dvander@1269: m_pVoteResults->PushCell(client_array_address);
dvander@1269: m_pVoteResults->PushCell(results->num_items);
dvander@1269: m_pVoteResults->PushCell(item_array_address);
dvander@1269: m_pVoteResults->Execute(NULL);
dvander@1269: }
dvander@1269:
dvander@1269: /* Free what we allocated, in reverse order as required */
dvander@1269: if (item_array_address != -1)
dvander@1269: {
dvander@1269: pContext->HeapPop(item_array_address);
dvander@1269: }
dvander@1269: if (client_array_address != -1)
dvander@1269: {
dvander@1269: pContext->HeapPop(client_array_address);
dvander@1269: }
dvander@1269: }
dvander@1269: }
dvander@1269:
dvander@1269: bool CMenuHandler::OnSetHandlerOption(const char *option, const void *data)
dvander@1269: {
dvander@1269: if (strcmp(option, "set_vote_results_handler") == 0)
dvander@1269: {
dvander@1269: void **array = (void **)data;
dvander@1269: m_pVoteResults = (IPluginFunction *)array[0];
dvander@1269: m_fnVoteResult = *(cell_t *)((cell_t *)array[1]);
dvander@1269: return true;
dvander@1269: }
dvander@1269:
dvander@1269: return false;
dvander@1269: }
dvander@1269:
dvander@790: /**
dvander@790: * INLINE FUNCTIONS FOR NATIVES
dvander@790: */
dvander@790:
dvander@790: inline Handle_t MakePanelHandle(IMenuPanel *panel, IPluginContext *pContext)
dvander@790: {
dvander@790: return g_HandleSys.CreateHandle(g_MenuHelpers.GetPanelType(), panel, pContext->GetIdentity(), g_pCoreIdent, NULL);
dvander@790: }
dvander@790:
dvander@790: inline HandleError ReadPanelHandle(Handle_t hndl, IMenuPanel **panel)
dvander@790: {
dvander@790: HandleSecurity sec;
dvander@790: sec.pIdentity = g_pCoreIdent;
dvander@790: sec.pOwner = NULL;
dvander@790: return g_HandleSys.ReadHandle(hndl, g_MenuHelpers.GetPanelType(), &sec, (void **)panel);
dvander@790: }
dvander@790:
dvander@790: inline IMenuStyle *GetStyleFromCell(cell_t cell)
dvander@790: {
dvander@790: enum MenuStyle
dvander@790: {
dvander@790: MenuStyle_Default = 0, /**< The "default" menu style for the mod */
dvander@790: MenuStyle_Valve = 1, /**< The Valve provided menu style (Used on HL2DM) */
dvander@790: MenuStyle_Radio = 2, /**< The simpler menu style commonly used on CS:S */
dvander@790: };
dvander@790:
dvander@790: if (cell == MenuStyle_Valve)
dvander@790: {
dvander@790: return &g_ValveMenuStyle;
dvander@790: } else if (cell == MenuStyle_Radio
dvander@790: && g_RadioMenuStyle.IsSupported())
dvander@790: {
dvander@790: return &g_RadioMenuStyle;
dvander@790: }
dvander@790:
dvander@790: return g_Menus.GetDefaultStyle();
dvander@790: }
dvander@790:
dvander@790: /***********************************
dvander@790: **** NATIVE DEFINITIONS ***********
dvander@790: ***********************************/
dvander@790:
dvander@790: static cell_t CreateMenu(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: IMenuStyle *style = g_Menus.GetDefaultStyle();
dvander@790: IPluginFunction *pFunction;
dvander@790:
dvander@790: if ((pFunction=pContext->GetFunctionById(params[1])) == NULL)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Function id %x is invalid", params[1]);
dvander@790: }
dvander@790:
dvander@790: CMenuHandler *handler = g_MenuHelpers.GetMenuHandler(pFunction, params[2]);
dvander@790: IBaseMenu *menu = style->CreateMenu(handler, pContext->GetIdentity());
dvander@790:
dvander@790: Handle_t hndl = menu->GetHandle();
dvander@790: if (!hndl)
dvander@790: {
dvander@790: menu->Destroy();
dvander@790: return BAD_HANDLE;
dvander@790: }
dvander@790:
dvander@790: return hndl;
dvander@790: }
dvander@790:
dvander@790: static cell_t DisplayMenu(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IBaseMenu *menu;
dvander@790:
dvander@790: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@790: return menu->Display(params[2], params[3]) ? 1 : 0;
dvander@790: }
dvander@790:
dvander@1476: static cell_t DisplayMenuAtItem(IPluginContext *pContext, const cell_t *params)
dvander@1476: {
dvander@1476: Handle_t hndl = (Handle_t)params[1];
dvander@1476: HandleError err;
dvander@1476: IBaseMenu *menu;
dvander@1476:
dvander@1476: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@1476: {
dvander@1476: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@1476: }
dvander@1476:
dvander@1476: return menu->DisplayAtItem(params[2], params[4], params[3]) ? 1 : 0;
dvander@1476: }
dvander@1476:
dvander@878: static cell_t VoteMenu(IPluginContext *pContext, const cell_t *params)
dvander@878: {
dvander@1269: if (g_Menus.IsVoteInProgress())
dvander@1269: {
dvander@1269: return pContext->ThrowNativeError("A vote is already in progress");
dvander@1269: }
dvander@1269:
dvander@878: Handle_t hndl = (Handle_t)params[1];
dvander@878: HandleError err;
dvander@878: IBaseMenu *menu;
dvander@878:
dvander@878: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@878: {
dvander@878: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@878: }
dvander@878:
dvander@878: cell_t *addr;
dvander@878: pContext->LocalToPhysAddr(params[2], &addr);
dvander@878:
dvander@1269: if (!g_Menus.StartVote(menu, params[3], addr, params[4]))
dvander@1269: {
dvander@1269: return 0;
dvander@1269: }
dvander@1269:
dvander@1269: return 1;
dvander@878: }
dvander@878:
dvander@790: static cell_t AddMenuItem(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IBaseMenu *menu;
dvander@790:
dvander@790: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@790: char *info;
dvander@790: ItemDrawInfo dr;
dvander@790:
dvander@790: pContext->LocalToString(params[2], &info);
dvander@790: pContext->LocalToString(params[3], (char **)&dr.display);
dvander@790: dr.style = params[4];
dvander@790:
dvander@790: return menu->AppendItem(info, dr) ? 1 : 0;
dvander@790: }
dvander@790:
dvander@790: static cell_t InsertMenuItem(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IBaseMenu *menu;
dvander@790:
dvander@790: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@790: char *info;
dvander@790: ItemDrawInfo dr;
dvander@790:
dvander@790: pContext->LocalToString(params[3], &info);
dvander@790: pContext->LocalToString(params[4], (char **)&dr.display);
dvander@790: dr.style = params[5];
dvander@790:
dvander@790: return menu->InsertItem(params[2], info, dr) ? 1 : 0;
dvander@790: }
dvander@790:
dvander@790: static cell_t RemoveMenuItem(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IBaseMenu *menu;
dvander@790:
dvander@790: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@790: return menu->RemoveItem(params[2]) ? 1 : 0;
dvander@790: }
dvander@790:
dvander@790: static cell_t RemoveAllMenuItems(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IBaseMenu *menu;
dvander@790:
dvander@790: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@790: menu->RemoveAllItems();
dvander@790:
dvander@790: return 1;
dvander@790: }
dvander@790:
dvander@790: static cell_t GetMenuItem(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IBaseMenu *menu;
dvander@790:
dvander@790: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@790: ItemDrawInfo dr;
dvander@790: const char *info;
dvander@790:
dvander@790: if ((info=menu->GetItemInfo(params[2], &dr)) == NULL)
dvander@790: {
dvander@790: return 0;
dvander@790: }
dvander@790:
dvander@790: pContext->StringToLocalUTF8(params[3], params[4], info, NULL);
dvander@790: pContext->StringToLocalUTF8(params[6], params[7], dr.display ? dr.display : "", NULL);
dvander@790:
dvander@790: cell_t *addr;
dvander@790: pContext->LocalToPhysAddr(params[5], &addr);
dvander@790: *addr = dr.style;
dvander@790:
dvander@790: return 1;
dvander@790: }
dvander@790:
dvander@790: static cell_t SetMenuPagination(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IBaseMenu *menu;
dvander@790:
dvander@790: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@790: return menu->SetPagination(params[2]) ? 1 : 0;
dvander@790: }
dvander@790:
dvander@790: static cell_t GetMenuPagination(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IBaseMenu *menu;
dvander@790:
dvander@790: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@790: return menu->GetPagination();
dvander@790: }
dvander@790:
dvander@790: static cell_t GetMenuItemCount(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IBaseMenu *menu;
dvander@790:
dvander@790: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@790: return menu->GetItemCount();
dvander@790: }
dvander@790:
dvander@790: static cell_t SetMenuTitle(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IBaseMenu *menu;
dvander@790:
dvander@790: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@2042: g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
dvander@1011:
dvander@790: char buffer[1024];
dvander@790: g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
dvander@790:
dvander@790: menu->SetDefaultTitle(buffer);
dvander@790:
dvander@790: return 1;
dvander@790: }
dvander@790:
dvander@1290: static cell_t GetMenuTitle(IPluginContext *pContext, const cell_t *params)
dvander@1290: {
dvander@1290: Handle_t hndl = (Handle_t)params[1];
dvander@1290: HandleError err;
dvander@1290: IBaseMenu *menu;
dvander@1290:
dvander@1290: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@1290: {
dvander@1290: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@1290: }
dvander@1290:
dvander@1290: size_t written;
dvander@1290: const char *title = menu->GetDefaultTitle();
dvander@1290: pContext->StringToLocalUTF8(params[2], params[3], title, &written);
dvander@1290:
dvander@1290: return (cell_t)written;
dvander@1290: }
dvander@1290:
dvander@1290:
dvander@790: static cell_t CreatePanelFromMenu(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IBaseMenu *menu;
dvander@790:
dvander@790: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@790: IMenuPanel *panel = menu->CreatePanel();
dvander@790: hndl = MakePanelHandle(panel, pContext);
dvander@790: if (!hndl)
dvander@790: {
dvander@790: panel->DeleteThis();
dvander@790: }
dvander@790:
dvander@790: return hndl;
dvander@790: }
dvander@790:
dvander@790: static cell_t GetMenuExitButton(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IBaseMenu *menu;
dvander@790:
dvander@790: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@1269: return ((menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT) ? 1 : 0;
dvander@790: }
dvander@790:
dvander@1005: static cell_t GetMenuExitBackButton(IPluginContext *pContext, const cell_t *params)
dvander@1005: {
dvander@1005: Handle_t hndl = (Handle_t)params[1];
dvander@1005: HandleError err;
dvander@1005: IBaseMenu *menu;
dvander@1005:
dvander@1005: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@1005: {
dvander@1005: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@1005: }
dvander@1005:
dvander@1269: return ((menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXITBACK) == MENUFLAG_BUTTON_EXIT) ? 1 : 0;
dvander@1005: }
dvander@1005:
dvander@790: static cell_t SetMenuExitButton(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IBaseMenu *menu;
dvander@790:
dvander@790: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@1269: unsigned int flags = menu->GetMenuOptionFlags();
dvander@1368:
dvander@1368: if (params[2])
dvander@1368: {
dvander@1368: flags |= MENUFLAG_BUTTON_EXIT;
dvander@1368: } else {
dvander@1368: flags &= ~MENUFLAG_BUTTON_EXIT;
dvander@1368: }
dvander@1368:
dvander@1269: menu->SetMenuOptionFlags(flags);
dvander@1368: unsigned int new_flags = menu->GetMenuOptionFlags();
dvander@1368:
dvander@1368: return (flags == new_flags);
dvander@790: }
dvander@790:
dvander@1005: static cell_t SetMenuExitBackButton(IPluginContext *pContext, const cell_t *params)
dvander@1005: {
dvander@1005: Handle_t hndl = (Handle_t)params[1];
dvander@1005: HandleError err;
dvander@1005: IBaseMenu *menu;
dvander@1005:
dvander@1005: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@1005: {
dvander@1005: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@1005: }
dvander@1005:
dvander@1269: unsigned int flags = menu->GetMenuOptionFlags();
dvander@1368:
dvander@1368: if (params[2])
dvander@1368: {
dvander@1368: flags |= MENUFLAG_BUTTON_EXITBACK;
dvander@1368: } else {
dvander@1368: flags &= ~MENUFLAG_BUTTON_EXITBACK;
dvander@1368: }
dvander@1368:
dvander@1269: menu->SetMenuOptionFlags(flags);
dvander@1005:
dvander@1005: return 1;
dvander@1005: }
dvander@1005:
dvander@790: static cell_t CancelMenu(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IBaseMenu *menu;
dvander@790:
dvander@790: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@1269: g_Menus.CancelMenu(menu);
dvander@790:
dvander@790: return 1;
dvander@790: }
dvander@790:
dvander@885: static cell_t IsVoteInProgress(IPluginContext *pContext, const cell_t *params)
dvander@885: {
dvander@1269: return g_Menus.IsVoteInProgress() ? 1 : 0;
dvander@885: }
dvander@885:
dvander@790: static cell_t GetMenuStyle(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IBaseMenu *menu;
dvander@790:
dvander@790: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@790: return menu->GetDrawStyle()->GetHandle();
dvander@790: }
dvander@790:
dvander@790: static cell_t GetMenuStyleHandle(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: IMenuStyle *style = GetStyleFromCell(params[1]);
dvander@790: if (!style)
dvander@790: {
dvander@790: return BAD_HANDLE;
dvander@790: }
dvander@790:
dvander@790: return style->GetHandle();
dvander@790: }
dvander@790:
dvander@790: static cell_t CreatePanel(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IMenuStyle *style;
dvander@790:
dvander@790: if (hndl != 0)
dvander@790: {
dvander@790: if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790: } else {
dvander@790: style = g_Menus.GetDefaultStyle();
dvander@790: }
dvander@790:
dvander@790: IMenuPanel *panel = style->CreatePanel();
dvander@790:
dvander@790: hndl = MakePanelHandle(panel, pContext);
dvander@790: if (!hndl)
dvander@790: {
dvander@790: panel->DeleteThis();
dvander@790: return BAD_HANDLE;
dvander@790: }
dvander@790:
dvander@790: return hndl;
dvander@790: }
dvander@790:
dvander@790: static cell_t CreateMenuEx(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IMenuStyle *style;
dvander@790:
dvander@790: if (hndl != 0)
dvander@790: {
dvander@790: if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790: } else {
dvander@790: style = g_Menus.GetDefaultStyle();
dvander@790: }
dvander@790:
dvander@790: IPluginFunction *pFunction;
dvander@790: if ((pFunction=pContext->GetFunctionById(params[2])) == NULL)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Function id %x is invalid", params[2]);
dvander@790: }
dvander@790:
dvander@790: CMenuHandler *handler = g_MenuHelpers.GetMenuHandler(pFunction, params[3]);
dvander@790:
dvander@790: IBaseMenu *pMenu = style->CreateMenu(handler, pContext->GetIdentity());
dvander@790: hndl = pMenu->GetHandle();
dvander@790: if (!hndl)
dvander@790: {
dvander@790: pMenu->Destroy();
dvander@790: return BAD_HANDLE;
dvander@790: }
dvander@790:
dvander@790: return hndl;
dvander@790: }
dvander@790:
dvander@790: static cell_t GetClientMenu(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[2];
dvander@790: HandleError err;
dvander@790: IMenuStyle *style;
dvander@790:
dvander@790: if (hndl != 0)
dvander@790: {
dvander@790: if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790: } else {
dvander@790: style = g_Menus.GetDefaultStyle();
dvander@790: }
dvander@790:
dvander@790: return style->GetClientMenu(params[1], NULL);
dvander@790: }
dvander@790:
dvander@790: static cell_t CancelClientMenu(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[3];
dvander@790: HandleError err;
dvander@790: IMenuStyle *style;
dvander@790:
dvander@790: if (hndl != 0)
dvander@790: {
dvander@790: if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790: } else {
dvander@790: style = g_Menus.GetDefaultStyle();
dvander@790: }
dvander@790:
dvander@790: return style->CancelClientMenu(params[1], params[2] ? true : false) ? 1 : 0;
dvander@790: }
dvander@790:
dvander@790: static cell_t GetMaxPageItems(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IMenuStyle *style;
dvander@790:
dvander@790: if (hndl != 0)
dvander@790: {
dvander@790: if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790: } else {
dvander@790: style = g_Menus.GetDefaultStyle();
dvander@790: }
dvander@790:
dvander@790: return style->GetMaxPageItems();
dvander@790: }
dvander@790:
dvander@790: static cell_t GetPanelStyle(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IMenuPanel *panel;
dvander@790:
dvander@790: if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@790: return panel->GetParentStyle()->GetHandle();
dvander@790: }
dvander@790:
dvander@790: static cell_t SetPanelTitle(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IMenuPanel *panel;
dvander@790:
dvander@790: if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@790: char *text;
dvander@790: pContext->LocalToString(params[2], &text);
dvander@790:
dvander@790: panel->DrawTitle(text, params[3] ? true : false);
dvander@790:
dvander@790: return 1;
dvander@790: }
dvander@790:
dvander@790: static cell_t DrawPanelItem(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IMenuPanel *panel;
dvander@790:
dvander@790: if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@790: ItemDrawInfo dr;
dvander@790: pContext->LocalToString(params[2], (char **)&dr.display);
dvander@790: dr.style = params[3];
dvander@790:
dvander@790: return panel->DrawItem(dr);
dvander@790: }
dvander@790:
dvander@790: static cell_t DrawPanelText(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IMenuPanel *panel;
dvander@790:
dvander@790: if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@790: char *text;
dvander@790: pContext->LocalToString(params[2], &text);
dvander@790:
dvander@790: return panel->DrawRawLine(text) ? 1 : 0;
dvander@790: }
dvander@790:
dvander@790: static cell_t CanPanelDrawFlags(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IMenuPanel *panel;
dvander@790:
dvander@790: if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@790: return panel->CanDrawItem(params[2]);
dvander@790: }
dvander@790:
dvander@790: static cell_t SendPanelToClient(IPluginContext *pContext, const cell_t *params)
dvander@790: {
dvander@790: Handle_t hndl = (Handle_t)params[1];
dvander@790: HandleError err;
dvander@790: IMenuPanel *panel;
dvander@790:
dvander@790: if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@790: }
dvander@790:
dvander@790: IPluginFunction *pFunction;
dvander@790: if ((pFunction=pContext->GetFunctionById(params[3])) == NULL)
dvander@790: {
dvander@790: return pContext->ThrowNativeError("Function id %x is invalid", params[3]);
dvander@790: }
dvander@790:
dvander@790: CPanelHandler *handler = g_MenuHelpers.GetPanelHandler(pFunction);
dvander@790: if (!panel->SendDisplay(params[2], handler, params[4]))
dvander@790: {
dvander@790: g_MenuHelpers.FreePanelHandler(handler);
dvander@790: }
dvander@790:
dvander@790: return 1;
dvander@790: }
dvander@790:
dvander@819: static cell_t SetPanelKeys(IPluginContext *pContext, const cell_t *params)
dvander@819: {
dvander@819: Handle_t hndl = (Handle_t)params[1];
dvander@819: HandleError err;
dvander@819: IMenuPanel *panel;
dvander@819:
dvander@819: if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
dvander@819: {
dvander@819: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@819: }
dvander@819:
dvander@819: return panel->SetSelectableKeys(params[2]);
dvander@819: }
dvander@819:
dvander@840: static cell_t GetPanelCurrentKey(IPluginContext *pContext, const cell_t *params)
dvander@840: {
dvander@840: Handle_t hndl = (Handle_t)params[1];
dvander@840: HandleError err;
dvander@840: IMenuPanel *panel;
dvander@840:
dvander@840: if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
dvander@840: {
dvander@840: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@840: }
dvander@840:
dvander@840: return panel->GetCurrentKey();
dvander@840: }
dvander@840:
dvander@1361: static cell_t GetPanelTextRemaining(IPluginContext *pContext, const cell_t *params)
dvander@1361: {
dvander@1361: Handle_t hndl = (Handle_t)params[1];
dvander@1361: HandleError err;
dvander@1361: IMenuPanel *panel;
dvander@1361:
dvander@1361: if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
dvander@1361: {
dvander@1361: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@1361: }
dvander@1361:
dvander@1361: return panel->GetAmountRemaining();
dvander@1361: }
dvander@1361:
dvander@840: static cell_t SetPanelCurrentKey(IPluginContext *pContext, const cell_t *params)
dvander@840: {
dvander@840: Handle_t hndl = (Handle_t)params[1];
dvander@840: HandleError err;
dvander@840: IMenuPanel *panel;
dvander@840:
dvander@840: if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
dvander@840: {
dvander@840: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@840: }
dvander@840:
dvander@840: return panel->SetCurrentKey(params[2]) ? 1 : 0;
dvander@840: }
dvander@840:
dvander@1163: static cell_t RedrawMenuItem(IPluginContext *pContext, const cell_t *params)
dvander@1163: {
dvander@1163: if (!s_pCurPanel)
dvander@1163: {
dvander@1163: return pContext->ThrowNativeError("You can only call this once from a MenuAction_DisplayItem callback");
dvander@1163: }
dvander@1163:
dvander@1163: char *str;
dvander@1163: pContext->LocalToString(params[1], &str);
dvander@1163:
dvander@1163: ItemDrawInfo dr = *s_CurDrawInfo;
dvander@1163: dr.display = str;
dvander@1163:
dvander@1163: if ((s_CurPanelReturn = s_pCurPanel->DrawItem(dr)) != 0)
dvander@1163: {
dvander@1163: s_pCurPanel = NULL;
dvander@1163: }
dvander@1163:
dvander@1163: return s_CurPanelReturn;
dvander@1163: }
dvander@1163:
dvander@1259: static cell_t GetMenuOptionFlags(IPluginContext *pContext, const cell_t *params)
dvander@1259: {
dvander@1259: Handle_t hndl = (Handle_t)params[1];
dvander@1259: HandleError err;
dvander@1259: IBaseMenu *menu;
dvander@1259:
dvander@1259: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@1259: {
dvander@1259: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@1259: }
dvander@1259:
dvander@1259: return menu->GetMenuOptionFlags();
dvander@1259: }
dvander@1259:
dvander@1259: static cell_t SetMenuOptionFlags(IPluginContext *pContext, const cell_t *params)
dvander@1259: {
dvander@1259: Handle_t hndl = (Handle_t)params[1];
dvander@1259: HandleError err;
dvander@1259: IBaseMenu *menu;
dvander@1259:
dvander@1259: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@1259: {
dvander@1259: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@1259: }
dvander@1259:
dvander@1259: menu->SetMenuOptionFlags(params[2]);
dvander@1259:
dvander@1259: return 1;
dvander@1259: }
dvander@1259:
dvander@1269: static cell_t CancelVote(IPluginContext *pContxt, const cell_t *params)
dvander@1269: {
dvander@1269: if (!g_Menus.IsVoteInProgress())
dvander@1269: {
dvander@1269: return pContxt->ThrowNativeError("No vote is in progress");
dvander@1269: }
dvander@1269:
dvander@1269: g_Menus.CancelVoting();
dvander@1269:
dvander@1269: return 1;
dvander@1269: }
dvander@1269:
dvander@1269: static cell_t SetVoteResultCallback(IPluginContext *pContext, const cell_t *params)
dvander@1269: {
dvander@1269: Handle_t hndl = (Handle_t)params[1];
dvander@1269: HandleError err;
dvander@1269: IBaseMenu *menu;
dvander@1269:
dvander@1269: if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
dvander@1269: {
dvander@1269: return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
dvander@1269: }
dvander@1269:
dvander@1269: IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
dvander@1269: if (!pFunction)
dvander@1269: {
dvander@1269: return pContext->ThrowNativeError("Invalid function %x", params[2]);
dvander@1269: }
dvander@1269:
dvander@1269: void *array[2];
dvander@1269: array[0] = pFunction;
dvander@1269: array[1] = (void *)¶ms[2];
dvander@1269:
dvander@1269: IMenuHandler *pHandler = menu->GetHandler();
dvander@1269: if (!pHandler->OnSetHandlerOption("set_vote_results_handler", (const void *)array))
dvander@1269: {
dvander@1269: return pContext->ThrowNativeError("The given menu does not support this option");
dvander@1269: }
dvander@1269:
dvander@1269: return 1;
dvander@1269: }
dvander@1269:
dvander@1291: static cell_t CheckVoteDelay(IPluginContext *pContext, const cell_t *params)
dvander@1291: {
dvander@1291: return g_Menus.GetRemainingVoteDelay();
dvander@1291: }
dvander@1291:
dvander@1476: static cell_t GetMenuSelectionPosition(IPluginContext *pContext, const cell_t *params)
dvander@1476: {
dvander@1476: if (!s_CurSelectPosition)
dvander@1476: {
dvander@1476: return pContext->ThrowNativeError("Can only be called from inside a MenuAction_Select callback");
dvander@1476: }
dvander@1476:
dvander@1476: return *s_CurSelectPosition;
dvander@1476: }
dvander@1476:
dvander@2056: static cell_t IsClientInVotePool(IPluginContext *pContext, const cell_t *params)
dvander@2056: {
dvander@2056: int client;
dvander@2056: IGamePlayer *pPlayer;
dvander@2056:
dvander@2056: client = params[1];
dvander@2056: if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
dvander@2056: {
dvander@2056: return pContext->ThrowNativeError("Invalid client index %d", client);
dvander@2056: }
dvander@2056:
dvander@2056: if (!g_Menus.IsVoteInProgress())
dvander@2056: {
dvander@2056: return pContext->ThrowNativeError("No vote is in progress");
dvander@2056: }
dvander@2056:
dvander@2056: return g_Menus.IsClientInVotePool(client) ? 1 : 0;
dvander@2056: }
dvander@2056:
dvander@2056: static cell_t RedrawClientVoteMenu(IPluginContext *pContext, const cell_t *params)
dvander@2056: {
dvander@2056: int client;
dvander@2056: IGamePlayer *pPlayer;
dvander@2056:
dvander@2056: client = params[1];
dvander@2056: if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
dvander@2056: {
dvander@2056: return pContext->ThrowNativeError("Invalid client index %d", client);
dvander@2056: }
dvander@2056:
dvander@2056: if (!g_Menus.IsVoteInProgress())
dvander@2056: {
dvander@2056: return pContext->ThrowNativeError("No vote is in progress");
dvander@2056: }
dvander@2056:
dvander@2056: if (!g_Menus.IsClientInVotePool(client))
dvander@2056: {
dvander@2056: return pContext->ThrowNativeError("Client is not in the voting pool");
dvander@2056: }
dvander@2056:
dvander@2056: return g_Menus.RedrawClientVoteMenu(client) ? 1 : 0;
dvander@2056: }
dvander@2056:
dvander@1705: class EmptyMenuHandler : public IMenuHandler
dvander@1705: {
dvander@1705: public:
dvander@1705: } s_EmptyMenuHandler;
dvander@1705:
dvander@1705: static cell_t InternalShowMenu(IPluginContext *pContext, const cell_t *params)
dvander@1705: {
dvander@1705: int client = params[1];
dvander@1705: CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
dvander@1705:
dvander@1705: if (pPlayer == NULL)
dvander@1705: {
dvander@1705: return pContext->ThrowNativeError("Invalid client index %d", client);
dvander@1705: }
dvander@1705: else if (!pPlayer->IsInGame())
dvander@1705: {
dvander@1705: return pContext->ThrowNativeError("Client %d is not in game", client);
dvander@1705: }
dvander@1705:
dvander@1705: if (!g_RadioMenuStyle.IsSupported())
dvander@1705: {
dvander@1705: return pContext->ThrowNativeError("Radio menus are not supported on this mod");
dvander@1705: }
dvander@1705:
dvander@1705: char *str;
dvander@1705: pContext->LocalToString(params[2], &str);
dvander@1705:
dvander@1705: IMenuPanel *pPanel = g_RadioMenuStyle.MakeRadioDisplay(str, params[4]);
dvander@1705:
dvander@1705: if (pPanel == NULL)
dvander@1705: {
dvander@1705: return 0;
dvander@1705: }
dvander@1705:
dvander@1705: IMenuHandler *pHandler;
dvander@1705: CPanelHandler *pActualHandler = NULL;
dvander@1705: if (params[5] != -1)
dvander@1705: {
dvander@1705: IPluginFunction *pFunction = pContext->GetFunctionById(params[5]);
dvander@1705: if (pFunction == NULL)
dvander@1705: {
dvander@1705: return pContext->ThrowNativeError("Invalid function index %x", params[5]);
dvander@1705: }
dvander@1705: pActualHandler = g_MenuHelpers.GetPanelHandler(pFunction);
dvander@1705: }
dvander@1705:
dvander@1705: if (pActualHandler == NULL)
dvander@1705: {
dvander@1705: pHandler = &s_EmptyMenuHandler;
dvander@1705: }
dvander@1705: else
dvander@1705: {
dvander@1705: pHandler = pActualHandler;
dvander@1705: }
dvander@1705:
dvander@1705: bool bSuccess = pPanel->SendDisplay(client, pHandler, params[3]);
dvander@1705:
dvander@1705: pPanel->DeleteThis();
dvander@1705:
dvander@1705: if (!bSuccess && pActualHandler != NULL)
dvander@1705: {
dvander@1705: g_MenuHelpers.FreePanelHandler(pActualHandler);
dvander@1705: }
dvander@1705:
dvander@1705: return bSuccess ? 1 : 0;
dvander@1705: }
dvander@1705:
dvander@790: REGISTER_NATIVES(menuNatives)
dvander@790: {
dvander@790: {"AddMenuItem", AddMenuItem},
dvander@790: {"CanPanelDrawFlags", CanPanelDrawFlags},
dvander@790: {"CancelClientMenu", CancelClientMenu},
dvander@790: {"CancelMenu", CancelMenu},
dvander@1269: {"CancelVote", CancelVote},
dvander@1291: {"CheckVoteDelay", CheckVoteDelay},
dvander@790: {"CreateMenu", CreateMenu},
dvander@790: {"CreateMenuEx", CreateMenuEx},
dvander@790: {"CreatePanel", CreatePanel},
ds@874: {"CreatePanelFromMenu", CreatePanelFromMenu},
dvander@790: {"DisplayMenu", DisplayMenu},
dvander@1476: {"DisplayMenuAtItem", DisplayMenuAtItem},
dvander@790: {"DrawPanelItem", DrawPanelItem},
dvander@790: {"DrawPanelText", DrawPanelText},
dvander@790: {"GetClientMenu", GetClientMenu},
dvander@790: {"GetMaxPageItems", GetMaxPageItems},
dvander@1005: {"GetMenuExitBackButton", GetMenuExitBackButton},
dvander@790: {"GetMenuExitButton", GetMenuExitButton},
dvander@790: {"GetMenuItem", GetMenuItem},
dvander@790: {"GetMenuItemCount", GetMenuItemCount},
dvander@1259: {"GetMenuOptionFlags", GetMenuOptionFlags},
dvander@790: {"GetMenuPagination", GetMenuPagination},
dvander@1476: {"GetMenuSelectionPosition",GetMenuSelectionPosition},
dvander@790: {"GetMenuStyle", GetMenuStyle},
dvander@790: {"GetMenuStyleHandle", GetMenuStyleHandle},
dvander@1290: {"GetMenuTitle", GetMenuTitle},
dvander@1361: {"GetPanelTextRemaining", GetPanelTextRemaining},
dvander@840: {"GetPanelCurrentKey", GetPanelCurrentKey},
dvander@790: {"GetPanelStyle", GetPanelStyle},
dvander@790: {"InsertMenuItem", InsertMenuItem},
dvander@1705: {"InternalShowMenu", InternalShowMenu},
dvander@2056: {"IsClientInVotePool", IsClientInVotePool},
dvander@885: {"IsVoteInProgress", IsVoteInProgress},
dvander@2056: {"RedrawClientVoteMenu", RedrawClientVoteMenu},
dvander@1163: {"RedrawMenuItem", RedrawMenuItem},
dvander@790: {"RemoveAllMenuItems", RemoveAllMenuItems},
dvander@790: {"RemoveMenuItem", RemoveMenuItem},
dvander@790: {"SendPanelToClient", SendPanelToClient},
dvander@1005: {"SetMenuExitBackButton", SetMenuExitBackButton},
dvander@790: {"SetMenuExitButton", SetMenuExitButton},
dvander@1259: {"SetMenuOptionFlags", SetMenuOptionFlags},
dvander@790: {"SetMenuPagination", SetMenuPagination},
dvander@790: {"SetMenuTitle", SetMenuTitle},
dvander@840: {"SetPanelCurrentKey", SetPanelCurrentKey},
dvander@790: {"SetPanelTitle", SetPanelTitle},
dvander@819: {"SetPanelKeys", SetPanelKeys},
dvander@1269: {"SetVoteResultCallback", SetVoteResultCallback},
dvander@878: {"VoteMenu", VoteMenu},
dvander@790: {NULL, NULL},
dvander@790: };