diff --git a/extensions/topmenus/TopMenu.cpp b/extensions/topmenus/TopMenu.cpp index 43d62ea9..18d8e512 100644 --- a/extensions/topmenus/TopMenu.cpp +++ b/extensions/topmenus/TopMenu.cpp @@ -186,28 +186,14 @@ unsigned int TopMenu::AddToMenu2(const char *name, topmenu_category_t *parent_cat = NULL; if (type == TopMenuObject_Item) { - /* Check parent index. Note it will be >= 1 here. */ - if (parent > m_Objects.size() || m_Objects[parent - 1]->is_free) + size_t category_id; + if (!FindCategoryByObject(parent, &category_id)) { return 0; } + parent_obj = m_Objects[parent - 1]; - - /* Find an equivalent pointer in the category array. */ - for (size_t i = 0; i < m_Categories.size(); i++) - { - if (m_Categories[i]->obj == parent_obj) - { - parent_cat = m_Categories[i]; - break; - } - } - - /* If none was found, leave. */ - if (parent_cat == NULL) - { - return 0; - } + parent_cat = m_Categories[category_id]; } /* Re-use an old object pointer if we can. */ @@ -454,6 +440,82 @@ bool TopMenu::DisplayMenu(int client, unsigned int hold_time, TopMenuPosition po return return_value; } +bool TopMenu::DisplayMenuAtCategory(int client, unsigned int object_id) +{ + if (m_clients == NULL) + { + return false; + } + + IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client); + if (!pPlayer->IsInGame()) + { + return false; + } + + // Get the category this object is in. + size_t category_id; + if (!FindCategoryByObject(object_id, &category_id)) + { + return false; + } + + topmenu_category_t *category = m_Categories[category_id]; + + UpdateClientRoot(client, pPlayer); + + topmenu_player_t *pClient = &m_clients[client]; + if (pClient->root == NULL) + { + return false; + } + + if (!m_bCacheTitles) + { + char renderbuf[128]; + m_pTitle->OnTopMenuDisplayTitle(this, client, 0, renderbuf, sizeof(renderbuf)); + pClient->root->SetDefaultTitle(renderbuf); + } + + bool return_value = false; + + return_value = DisplayCategory(client, category_id, 0, true); + if (!return_value) + { + return_value = pClient->root->DisplayAtItem(client, 0, pClient->last_root_pos); + } + + return return_value; +} + +bool TopMenu::FindCategoryByObject(unsigned int obj_id, size_t *index) +{ + if (obj_id == 0 + || obj_id > m_Objects.size() + || m_Objects[obj_id - 1]->is_free) + { + return false; + } + + topmenu_object_t *obj = m_Objects[obj_id - 1]; + if (obj->type != TopMenuObject_Category) + { + return false; + } + + /* Find an equivalent pointer in the category array. */ + for (size_t i = 0; i < m_Categories.size(); i++) + { + if (m_Categories[i]->obj == obj) + { + *index = i; + return true; + } + } + + return false; +} + bool TopMenu::DisplayCategory(int client, unsigned int category, unsigned int hold_time, bool last_position) { UpdateClientCategory(client, category); diff --git a/extensions/topmenus/TopMenu.h b/extensions/topmenus/TopMenu.h index d85a0abd..b20f1afb 100644 --- a/extensions/topmenus/TopMenu.h +++ b/extensions/topmenus/TopMenu.h @@ -155,6 +155,7 @@ public: //ITextListener_SMC public: unsigned int CalcMemUsage(); void SetTitleCaching(bool cache_titles); + bool DisplayMenuAtCategory(int client, unsigned int object_id); private: void SortCategoriesIfNeeded(); void SortCategoryIfNeeded(unsigned int category); @@ -164,6 +165,7 @@ private: void UpdateClientRoot(int client, IGamePlayer *pGamePlayer=NULL); void UpdateClientCategory(int client, unsigned int category, bool bSkipRootCheck=false); void TearDownClient(topmenu_player_t *player); + bool FindCategoryByObject(unsigned int obj_id, size_t *index); private: void OnClientConnected(int client); void OnClientDisconnected(int client); diff --git a/extensions/topmenus/smn_topmenus.cpp b/extensions/topmenus/smn_topmenus.cpp index 2cd8db6b..5e190a43 100644 --- a/extensions/topmenus/smn_topmenus.cpp +++ b/extensions/topmenus/smn_topmenus.cpp @@ -326,6 +326,32 @@ static cell_t DisplayTopMenu(IPluginContext *pContext, const cell_t *params) return pMenu->DisplayMenu(client, 0, (TopMenuPosition)params[3]); } +static cell_t DisplayTopMenuCategory(IPluginContext *pContext, const cell_t *params) +{ + HandleError err; + TopMenu *pMenu; + HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity()); + + if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); + } + + int client = params[3]; + IGamePlayer *player = playerhelpers->GetGamePlayer(client); + if (!player) + { + return pContext->ThrowNativeError("Invalid client index %d", client); + } + else if (!player->IsInGame()) + { + return pContext->ThrowNativeError("Client %d is not in game", client); + } + + return pMenu->DisplayMenuAtCategory(client, params[2]); +} + static cell_t GetTopMenuInfoString(IPluginContext *pContext, const cell_t *params) { HandleError err; @@ -396,6 +422,7 @@ sp_nativeinfo_t g_TopMenuNatives[] = {"AddToTopMenu", AddToTopMenu}, {"CreateTopMenu", CreateTopMenu}, {"DisplayTopMenu", DisplayTopMenu}, + {"DisplayTopMenuCategory", DisplayTopMenuCategory}, {"LoadTopMenuConfig", LoadTopMenuConfig}, {"RemoveFromTopMenu", RemoveFromTopMenu}, {"FindTopMenuCategory", FindTopMenuCategory}, diff --git a/plugins/include/topmenus.inc b/plugins/include/topmenus.inc index f5ca0f67..a09860c5 100644 --- a/plugins/include/topmenus.inc +++ b/plugins/include/topmenus.inc @@ -247,6 +247,17 @@ native RemoveFromTopMenu(Handle:topmenu, TopMenuObject:object); */ native bool:DisplayTopMenu(Handle:topmenu, client, TopMenuPosition:position); +/** + * Displays a TopMenu category to a client. + * + * @param topmenu TopMenu Handle. + * @param category Category object id. + * @param client Client index. + * @return True on success, false on failure. + * @error Invalid TopMenu Handle or client not in game. + */ +native bool:DisplayTopMenuCategory(Handle:topmenu, TopMenuObject:category, client); + /** * Finds a category's object ID in a TopMenu. * @@ -296,6 +307,7 @@ public __ext_topmenus_SetNTVOptional() MarkNativeAsOptional("AddToTopMenu"); MarkNativeAsOptional("RemoveFromTopMenu"); MarkNativeAsOptional("DisplayTopMenu"); + MarkNativeAsOptional("DisplayTopMenuCategory"); MarkNativeAsOptional("FindTopMenuCategory"); MarkNativeAsOptional("SetTopMenuTitleCaching"); }