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