ds@1952: /** ds@1952: * vim: set ts=4 : ds@1952: * ============================================================================= ds@1952: * SourceMod ds@1952: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. ds@1952: * ============================================================================= ds@1952: * ds@1952: * This program is free software; you can redistribute it and/or modify it under ds@1952: * the terms of the GNU General Public License, version 3.0, as published by the ds@1952: * Free Software Foundation. ds@1952: * ds@1952: * This program is distributed in the hope that it will be useful, but WITHOUT ds@1952: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ds@1952: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ds@1952: * details. ds@1952: * ds@1952: * You should have received a copy of the GNU General Public License along with ds@1952: * this program. If not, see . ds@1952: * ds@1952: * As a special exception, AlliedModders LLC gives you permission to link the ds@1952: * code of this program (as well as its derivative works) to "Half-Life 2," the ds@1952: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software ds@1952: * by the Valve Corporation. You must obey the GNU General Public License in ds@1952: * all respects for all other code used. Additionally, AlliedModders LLC grants ds@1952: * this exception to all derivative works. AlliedModders LLC defines further ds@1952: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), ds@1952: * or . ds@1952: * ds@1952: * Version: $Id$ ds@1952: */ ds@1952: ds@1952: #include ds@1952: #include ds@1952: #include ds@1952: #include "MenuManager.h" ds@1952: #include "MenuVoting.h" ds@1952: #include "sm_stringutil.h" ds@1952: #include "sourcemm_api.h" ds@1952: #include "PlayerManager.h" ds@1952: #include "MenuStyle_Valve.h" ds@1952: #include "ShareSys.h" ds@1952: #include "HandleSys.h" ds@1952: #include "sourcemm_api.h" ds@1952: ds@1952: MenuManager g_Menus; ds@1952: VoteMenuHandler s_VoteHandler; ds@1952: ds@1952: ConVar sm_menu_sounds("sm_menu_sounds", "1", 0, "Sets whether SourceMod menus play trigger sounds"); ds@1952: ds@1952: MenuManager::MenuManager() ds@1952: { ds@1952: m_Styles.push_back(&g_ValveMenuStyle); ds@1952: SetDefaultStyle(&g_ValveMenuStyle); ds@1952: } ds@1952: ds@1952: void MenuManager::OnSourceModAllInitialized() ds@1952: { ds@1952: g_ShareSys.AddInterface(NULL, this); ds@1952: ds@1952: HandleAccess access; ds@1952: g_HandleSys.InitAccessDefaults(NULL, &access); ds@1952: ds@1952: /* Deny cloning to menus */ ds@1952: access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY; ds@1952: m_MenuType = g_HandleSys.CreateType("IBaseMenu", this, 0, NULL, &access, g_pCoreIdent, NULL); ds@1952: ds@1952: /* Also deny deletion to styles */ ds@1952: access.access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY; ds@1952: m_StyleType = g_HandleSys.CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL); ds@1952: } ds@1952: ds@1952: void MenuManager::OnSourceModAllShutdown() ds@1952: { ds@1952: g_HandleSys.RemoveType(m_MenuType, g_pCoreIdent); ds@1952: g_HandleSys.RemoveType(m_StyleType, g_pCoreIdent); ds@1952: } ds@1952: ds@1952: void MenuManager::OnHandleDestroy(HandleType_t type, void *object) ds@1952: { ds@1952: if (type == m_MenuType) ds@1952: { ds@1952: IBaseMenu *menu = (IBaseMenu *)object; ds@1952: menu->Destroy(false); ds@1952: } ds@1952: else if (type == m_StyleType) ds@1952: { ds@1952: /* Do nothing */ ds@1952: } ds@1952: } ds@1952: ds@1952: bool MenuManager::GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) ds@1952: { ds@1952: if (type == m_MenuType) ds@1952: { ds@1952: *pSize = ((IBaseMenu *)object)->GetApproxMemUsage(); ds@1952: return true; ds@1952: } ds@1952: else ds@1952: { ds@1952: *pSize = ((IMenuStyle *)object)->GetApproxMemUsage(); ds@1952: return true; ds@1952: } ds@1952: ds@1952: return false; ds@1952: } ds@1952: ds@1952: Handle_t MenuManager::CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner) ds@1952: { ds@1952: if (m_MenuType == NO_HANDLE_TYPE) ds@1952: { ds@1952: return BAD_HANDLE; ds@1952: } ds@1952: ds@1952: return g_HandleSys.CreateHandle(m_MenuType, menu, pOwner, g_pCoreIdent, NULL); ds@1952: } ds@1952: ds@1952: Handle_t MenuManager::CreateStyleHandle(IMenuStyle *style) ds@1952: { ds@1952: if (m_StyleType == NO_HANDLE_TYPE) ds@1952: { ds@1952: return BAD_HANDLE; ds@1952: } ds@1952: ds@1952: return g_HandleSys.CreateHandle(m_StyleType, style, g_pCoreIdent, g_pCoreIdent, NULL); ds@1952: } ds@1952: ds@1952: HandleError MenuManager::ReadMenuHandle(Handle_t handle, IBaseMenu **menu) ds@1952: { ds@1952: HandleSecurity sec; ds@1952: ds@1952: sec.pIdentity = g_pCoreIdent; ds@1952: sec.pOwner = NULL; ds@1952: ds@1952: return g_HandleSys.ReadHandle(handle, m_MenuType, &sec, (void **)menu); ds@1952: } ds@1952: ds@1952: HandleError MenuManager::ReadStyleHandle(Handle_t handle, IMenuStyle **style) ds@1952: { ds@1952: HandleSecurity sec; ds@1952: ds@1952: sec.pIdentity = g_pCoreIdent; ds@1952: sec.pOwner = g_pCoreIdent; ds@1952: ds@1952: return g_HandleSys.ReadHandle(handle, m_StyleType, &sec, (void **)style); ds@1952: } ds@1952: ds@1952: bool MenuManager::SetDefaultStyle(IMenuStyle *style) ds@1952: { ds@1952: if (!style) ds@1952: { ds@1952: return false; ds@1952: } ds@1952: ds@1952: m_pDefaultStyle = style; ds@1952: ds@1952: return true; ds@1952: } ds@1952: ds@1952: IMenuStyle *MenuManager::GetStyle(unsigned int index) ds@1952: { ds@1952: if (index >= GetStyleCount()) ds@1952: { ds@1952: return NULL; ds@1952: } ds@1952: ds@1952: return m_Styles[index]; ds@1952: } ds@1952: ds@1952: void MenuManager::AddStyle(IMenuStyle *style) ds@1952: { ds@1952: m_Styles.push_back(style); ds@1952: } ds@1952: ds@1952: unsigned int MenuManager::GetStyleCount() ds@1952: { ds@1952: return (unsigned int)m_Styles.size(); ds@1952: } ds@1952: ds@1952: IMenuStyle *MenuManager::FindStyleByName(const char *name) ds@1952: { ds@1952: unsigned int count = GetStyleCount(); ds@1952: for (unsigned int i=0; iGetStyleName(), name) == 0) ds@1952: { ds@1952: return ptr; ds@1952: } ds@1952: } ds@1952: ds@1952: return NULL; ds@1952: } ds@1952: ds@1952: inline bool IsSlotItem(IMenuPanel *display, ds@1952: unsigned int style) ds@1952: { ds@1952: if (!display->CanDrawItem(style)) ds@1952: { ds@1952: return false; ds@1952: } ds@1952: if ((style & ITEMDRAW_IGNORE) == ITEMDRAW_IGNORE) ds@1952: { ds@1952: return false; ds@1952: } ds@1952: if (style & ITEMDRAW_RAWLINE) ds@1952: { ds@1952: return false; ds@1952: } ds@1952: ds@1952: return true; ds@1952: } ds@1952: ds@1952: IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder order) ds@1952: { ds@1952: IBaseMenu *menu = md.menu; ds@1952: ds@1952: if (!menu) ds@1952: { ds@1952: return NULL; ds@1952: } ds@1952: ds@1952: struct ds@1952: { ds@1952: unsigned int position; ds@1952: ItemDrawInfo draw; ds@1952: } drawItems[10]; ds@1952: ds@1952: /* Figure out how many items to draw */ ds@1952: IMenuStyle *style = menu->GetDrawStyle(); ds@1952: unsigned int pgn = menu->GetPagination(); ds@1952: unsigned int maxItems = style->GetMaxPageItems(); ds@1952: bool exitButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT; ds@1952: ds@1952: if (pgn != MENU_NO_PAGINATION) ds@1952: { ds@1952: maxItems = pgn; ds@1952: } ds@1952: else if (exitButton) ds@1952: { ds@1952: maxItems--; ds@1952: } ds@1952: ds@1952: /* This is very not allowed! */ ds@1952: if (maxItems < 2) ds@1952: { ds@1952: return NULL; ds@1952: } ds@1952: ds@1952: unsigned int totalItems = menu->GetItemCount(); ds@1952: unsigned int startItem = 0; ds@1952: ds@1952: /* For pagination, find the starting point. */ ds@1952: if (pgn != MENU_NO_PAGINATION) ds@1952: { ds@1952: if (order == ItemOrder_Ascending) ds@1952: { ds@1952: startItem = md.lastItem; ds@1952: /* This shouldn't happen with well-coded menus. ds@1952: * If the item is out of bounds, switch the order to ds@1952: * Items_Descending and make us start from the top. ds@1952: */ ds@1952: if (startItem >= totalItems) ds@1952: { ds@1952: startItem = totalItems - 1; ds@1952: order = ItemOrder_Descending; ds@1952: } ds@1952: } ds@1952: else if (order == ItemOrder_Descending) ds@1952: { ds@1952: startItem = md.firstItem; ds@1952: /* This shouldn't happen with well-coded menus. ds@1952: * If searching backwards doesn't give us enough room, ds@1952: * start from the beginning and change to ascending. ds@1952: */ ds@1952: if (startItem <= maxItems) ds@1952: { ds@1952: startItem = 0; ds@1952: order = ItemOrder_Ascending; ds@1952: } ds@1952: } ds@1952: } ds@1952: ds@1952: /* Get our Display pointer and initialize some crap */ ds@1952: IMenuPanel *panel = menu->CreatePanel(); ds@1952: IMenuHandler *mh = md.mh; ds@1952: bool foundExtra = false; ds@1952: unsigned int extraItem = 0; ds@1952: ds@1952: if (panel == NULL) ds@1952: { ds@1952: return NULL; ds@1952: } ds@1952: ds@1952: /** ds@1952: * We keep searching until: ds@1952: * 1) There are no more items ds@1952: * 2) We reach one OVER the maximum number of slot items ds@1952: * 3) We have reached maxItems and pagination is MENU_NO_PAGINATION ds@1952: */ ds@1952: unsigned int i = startItem; ds@1952: unsigned int foundItems = 0; ds@1952: while (totalItems) ds@1952: { ds@1952: ItemDrawInfo &dr = drawItems[foundItems].draw; ds@1952: /* Is the item valid? */ ds@1952: if (menu->GetItemInfo(i, &dr) != NULL) ds@1952: { ds@1952: /* Ask the user to change the style, if necessary */ ds@1952: mh->OnMenuDrawItem(menu, client, i, dr.style); ds@1952: /* Check if it's renderable */ ds@1952: if (IsSlotItem(panel, dr.style)) ds@1952: { ds@1952: /* If we've already found the max number of items, ds@1952: * This means we should just cancel out and log our ds@1952: * "last item." ds@1952: */ ds@1952: if (foundItems >= maxItems) ds@1952: { ds@1952: foundExtra = true; ds@1952: extraItem = i; ds@1952: break; ds@1952: } ds@1952: drawItems[foundItems++].position = i; ds@1952: } ds@1952: } ds@1952: /* If there's no pagination, stop once the menu is full. */ ds@1952: if (pgn == MENU_NO_PAGINATION) ds@1952: { ds@1952: /* If we've filled up, then stop */ ds@1952: if (foundItems >= maxItems) ds@1952: { ds@1952: break; ds@1952: } ds@1952: } ds@1952: /* If we're descending and this is the first item, stop */ ds@1952: if (order == ItemOrder_Descending) ds@1952: { ds@1952: if (i == 0) ds@1952: { ds@1952: break; ds@1952: } ds@1952: i--; ds@1952: } ds@1952: /* If we're ascending and this is the last item, stop */ ds@1952: else if (order == ItemOrder_Ascending) ds@1952: { ds@1952: if (i >= totalItems - 1) ds@1952: { ds@1952: break; ds@1952: } ds@1952: i++; ds@1952: } ds@1952: } ds@1952: ds@1952: /* There were no items to draw! */ ds@1952: if (!foundItems) ds@1952: { ds@1952: panel->DeleteThis(); ds@1952: return NULL; ds@1952: } ds@1952: ds@1952: bool displayPrev = false; ds@1952: bool displayNext = false; ds@1952: ds@1952: /* This is an annoying process. ds@1952: * Skip it for non-paginated menus, which get special treatment. ds@1952: */ ds@1952: if (pgn != MENU_NO_PAGINATION) ds@1952: { ds@1952: if (foundExtra) ds@1952: { ds@1952: if (order == ItemOrder_Descending) ds@1952: { ds@1952: displayPrev = true; ds@1952: md.firstItem = extraItem; ds@1952: } ds@1952: else if (order == ItemOrder_Ascending) ds@1952: { ds@1952: displayNext = true; ds@1952: md.lastItem = extraItem; ds@1952: } ds@1952: } ds@1952: ds@1952: unsigned int lastItem = 0; ds@1952: ItemDrawInfo dr; ds@1952: /* Find the last feasible item to search from. */ ds@1952: if (order == ItemOrder_Descending) ds@1952: { ds@1952: lastItem = drawItems[0].position; ds@1952: if (lastItem >= totalItems - 1) ds@1952: { ds@1952: goto skip_search; ds@1952: } ds@1952: while (++lastItem < totalItems) ds@1952: { ds@1952: if (menu->GetItemInfo(lastItem, &dr) != NULL) ds@1952: { ds@1952: mh->OnMenuDrawItem(menu, client, lastItem, dr.style); ds@1952: if (IsSlotItem(panel, dr.style)) ds@1952: { ds@1952: displayNext = true; ds@1952: md.lastItem = lastItem; ds@1952: break; ds@1952: } ds@1952: } ds@1952: } ds@1952: } ds@1952: else if (order == ItemOrder_Ascending) ds@1952: { ds@1952: lastItem = drawItems[0].position; ds@1952: if (lastItem == 0) ds@1952: { ds@1952: goto skip_search; ds@1952: } ds@1952: lastItem--; ds@1952: while (lastItem != 0) ds@1952: { ds@1952: if (menu->GetItemInfo(lastItem, &dr) != NULL) ds@1952: { ds@1952: mh->OnMenuDrawItem(menu, client, lastItem, dr.style); ds@1952: if (IsSlotItem(panel, dr.style)) ds@1952: { ds@1952: displayPrev = true; ds@1952: md.firstItem = lastItem; ds@1952: break; ds@1952: } ds@1952: } ds@1952: lastItem--; ds@1952: } ds@1952: } ds@1952: } ds@1952: ds@1952: skip_search: ds@1952: ds@1952: /* Draw the item according to the order */ ds@1952: menu_slots_t *slots = md.slots; ds@1952: unsigned int position = 0; /* Keep track of the last position */ ds@1952: if (order == ItemOrder_Ascending) ds@1952: { ds@1952: md.item_on_page = drawItems[0].position; ds@1952: for (unsigned int i = 0; i < foundItems; i++) ds@1952: { ds@1952: ItemDrawInfo &dr = drawItems[i].draw; ds@1952: if ((position = mh->OnMenuDisplayItem(menu, client, panel, drawItems[i].position, dr)) == 0) ds@1952: { ds@1952: position = panel->DrawItem(dr); ds@1952: } ds@1952: if (position != 0) ds@1952: { ds@1952: slots[position].item = drawItems[i].position; ds@1952: if ((dr.style & ITEMDRAW_DISABLED) == ITEMDRAW_DISABLED) ds@1952: { ds@1952: slots[position].type = ItemSel_None; ds@1952: } ds@1952: else ds@1952: { ds@1952: slots[position].type = ItemSel_Item; ds@1952: } ds@1952: } ds@1952: } ds@1952: } ds@1952: else if (order == ItemOrder_Descending) ds@1952: { ds@1952: unsigned int i = foundItems; ds@1952: /* NOTE: There will always be at least one item because ds@1952: * of the check earlier. ds@1952: */ ds@1952: md.item_on_page = drawItems[foundItems - 1].position; ds@1952: while (i--) ds@1952: { ds@1952: ItemDrawInfo &dr = drawItems[i].draw; ds@1952: if ((position = mh->OnMenuDisplayItem(menu, client, panel, drawItems[i].position, dr)) == 0) ds@1952: { ds@1952: position = panel->DrawItem(dr); ds@1952: } ds@1952: if (position != 0) ds@1952: { ds@1952: slots[position].item = drawItems[i].position; ds@1952: if ((dr.style & ITEMDRAW_DISABLED) == ITEMDRAW_DISABLED) ds@1952: { ds@1952: slots[position].type = ItemSel_None; ds@1952: } ds@1952: else ds@1952: { ds@1952: slots[position].type = ItemSel_Item; ds@1952: } ds@1952: } ds@1952: } ds@1952: } ds@1952: ds@1952: /* Now, we need to check if we need to add anything extra */ ds@1952: if (pgn != MENU_NO_PAGINATION || exitButton) ds@1952: { ds@1952: bool canDrawDisabled = panel->CanDrawItem(ITEMDRAW_DISABLED|ITEMDRAW_CONTROL); ds@1952: bool exitBackButton = false; ds@1952: char text[50]; ds@1952: ds@1952: if (pgn != MENU_NO_PAGINATION ds@1952: && (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXITBACK) == MENUFLAG_BUTTON_EXITBACK) ds@1952: { ds@1952: exitBackButton = true; ds@1952: } ds@1952: ds@1952: /* Calculate how many items we are allowed for control stuff */ ds@1952: unsigned int padding = style->GetMaxPageItems() - maxItems; ds@1952: ds@1952: /* Add the number of available slots */ ds@1952: padding += (maxItems - foundItems); ds@1952: ds@1952: /* Someday, if we are able to re-enable this, we will be very lucky men. */ ds@1952: #if 0 ds@1952: if (!style->FeatureExists(MenuStyleFeature_ImplicitExit)) ds@1952: { ds@1952: #endif ds@1952: /* Even if we don't draw an exit button, we invalidate the slot. */ ds@1952: padding--; ds@1952: #if 0 ds@1952: } else { ds@1952: /* Otherwise, we don't draw anything and leave the slot available */ ds@1952: exitButton = false; ds@1952: } ds@1952: #endif ds@1952: ds@1952: if (pgn != MENU_NO_PAGINATION) ds@1952: { ds@1952: /* Subtract two slots for the displayNext/displayPrev padding */ ds@1952: padding -= 2; ds@1952: } ds@1952: ds@1952: /* If we have an "Exit Back" button and the space to draw it, do so. */ ds@1952: if (exitBackButton) ds@1952: { ds@1952: if (!displayPrev) ds@1952: { ds@1952: displayPrev = true; ds@1952: } ds@1952: else ds@1952: { ds@1952: exitBackButton = false; ds@1952: } ds@1952: } ds@1952: ds@1952: /** ds@1952: * We allow next/prev to be undrawn if neither exists. ds@1952: * Thus, we only need padding if one of them will be drawn, ds@1952: * or the exit button will be drawn. ds@1952: */ ds@1952: ItemDrawInfo padItem(NULL, ITEMDRAW_SPACER); ds@1952: if (exitButton || (displayNext || displayPrev)) ds@1952: { ds@1952: /* If there are no control options, ds@1952: * Instead just pad with invisible slots. ds@1952: */ ds@1952: if (!displayPrev && !displayPrev) ds@1952: { ds@1952: padItem.style = ITEMDRAW_NOTEXT; ds@1952: } ds@1952: /* Add spacers so we can pad to the end */ ds@1952: for (unsigned int i=0; iDrawItem(padItem); ds@1952: slots[position].type = ItemSel_None; ds@1952: } ds@1952: } ds@1952: ds@1952: /* Put a fake spacer before control stuff, if possible */ ds@1952: if ((displayPrev || displayNext) || exitButton) ds@1952: { ds@1952: ItemDrawInfo draw("", ITEMDRAW_RAWLINE|ITEMDRAW_SPACER); ds@1952: panel->DrawItem(draw); ds@1952: } ds@1952: ds@1952: ItemDrawInfo dr(text, 0); ds@1952: ds@1952: /** ds@1952: * If we have one or the other, we need to have spacers for both. ds@1952: */ ds@1952: if (pgn != MENU_NO_PAGINATION) ds@1952: { ds@1952: if (displayPrev || displayNext) ds@1952: { ds@1952: /* PREVIOUS */ ds@1952: ItemDrawInfo padCtrlItem(NULL, ITEMDRAW_SPACER|ITEMDRAW_CONTROL); ds@1952: if (displayPrev || canDrawDisabled) ds@1952: { ds@1952: if (exitBackButton) ds@1952: { ds@1952: CorePlayerTranslate(client, text, sizeof(text), "Back", NULL); ds@1952: dr.style = ITEMDRAW_CONTROL; ds@1952: position = panel->DrawItem(dr); ds@1952: slots[position].type = ItemSel_ExitBack; ds@1952: } ds@1952: else ds@1952: { ds@1952: CorePlayerTranslate(client, text, sizeof(text), "Previous", NULL); ds@1952: dr.style = (displayPrev ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL; ds@1952: position = panel->DrawItem(dr); ds@1952: slots[position].type = ItemSel_Back; ds@1952: } ds@1952: } ds@1952: else if (displayNext || exitButton) ds@1952: { ds@1952: /* If we can't display this, and there is an exit button, ds@1952: * we need to pad! ds@1952: */ ds@1952: position = panel->DrawItem(padCtrlItem); ds@1952: slots[position].type = ItemSel_None; ds@1952: } ds@1952: ds@1952: /* NEXT */ ds@1952: if (displayNext || canDrawDisabled) ds@1952: { ds@1952: CorePlayerTranslate(client, text, sizeof(text), "Next", NULL); ds@1952: dr.style = (displayNext ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL; ds@1952: position = panel->DrawItem(dr); ds@1952: slots[position].type = ItemSel_Next; ds@1952: } ds@1952: else if (exitButton) ds@1952: { ds@1952: /* If we can't display this, ds@1952: * but there is an "exit" button, we need to pad! ds@1952: */ ds@1952: position = panel->DrawItem(padCtrlItem); ds@1952: slots[position].type = ItemSel_None; ds@1952: } ds@1952: } ds@1952: else ds@1952: { ds@1952: /* Otherwise, bump to two slots! */ ds@1952: ItemDrawInfo numBump(NULL, ITEMDRAW_NOTEXT); ds@1952: position = panel->DrawItem(numBump); ds@1952: slots[position].type = ItemSel_None; ds@1952: position = panel->DrawItem(numBump); ds@1952: slots[position].type = ItemSel_None; ds@1952: } ds@1952: } ds@1952: ds@1952: /* EXIT */ ds@1952: if (exitButton) ds@1952: { ds@1952: CorePlayerTranslate(client, text, sizeof(text), "Exit", NULL); ds@1952: dr.style = ITEMDRAW_CONTROL; ds@1952: position = panel->DrawItem(dr); ds@1952: slots[position].type = ItemSel_Exit; ds@1952: } ds@1952: } ds@1952: ds@1952: /* Lastly, fill in any slots we could have missed */ ds@1952: for (unsigned int i = position + 1; i < 10; i++) ds@1952: { ds@1952: slots[i].type = ItemSel_None; ds@1952: } ds@1952: ds@1952: /* Do title stuff */ ds@1952: mh->OnMenuDisplay(menu, client, panel); ds@1952: panel->DrawTitle(menu->GetDefaultTitle(), true); ds@1952: ds@1952: return panel; ds@1952: } ds@1952: ds@1952: IMenuStyle *MenuManager::GetDefaultStyle() ds@1952: { ds@1952: return m_pDefaultStyle; ds@1952: } ds@1952: ds@1952: bool MenuManager::MenuSoundsEnabled() ds@1952: { ds@1952: return (sm_menu_sounds.GetInt() != 0); ds@1952: } ds@1952: ds@1952: ConfigResult MenuManager::OnSourceModConfigChanged(const char *key, ds@1952: const char *value, ds@1952: ConfigSource source, ds@1952: char *error, ds@1952: size_t maxlength) ds@1952: { ds@1952: if (strcmp(key, "MenuItemSound") == 0) ds@1952: { ds@1952: m_SelectSound.assign(value); ds@1952: return ConfigResult_Accept; ds@1952: } else if (strcmp(key, "MenuExitBackSound") == 0) { ds@1952: m_ExitBackSound.assign(value); ds@1952: return ConfigResult_Accept; ds@1952: } else if (strcmp(key, "MenuExitSound") == 0) { ds@1952: m_ExitSound.assign(value); ds@1952: return ConfigResult_Accept; ds@1952: } ds@1952: ds@1952: return ConfigResult_Ignore; ds@1952: } ds@1952: ds@1952: const char *MenuManager::GetMenuSound(ItemSelection sel) ds@1952: { ds@1952: const char *sound = NULL; ds@1952: ds@1952: switch (sel) ds@1952: { ds@1952: case ItemSel_Back: ds@1952: case ItemSel_Next: ds@1952: case ItemSel_Item: ds@1952: { ds@1952: if (m_SelectSound.size() > 0) ds@1952: { ds@1952: sound = m_SelectSound.c_str(); ds@1952: } ds@1952: break; ds@1952: } ds@1952: case ItemSel_ExitBack: ds@1952: { ds@1952: if (m_ExitBackSound.size() > 0) ds@1952: { ds@1952: sound = m_ExitBackSound.c_str(); ds@1952: } ds@1952: break; ds@1952: } ds@1952: case ItemSel_Exit: ds@1952: { ds@1952: if (m_ExitSound.size() > 0) ds@1952: { ds@1952: sound = m_ExitSound.c_str(); ds@1952: } ds@1952: break; ds@1952: } ds@1952: default: ds@1952: { ds@1952: break; ds@1952: } ds@1952: } ds@1952: ds@1952: return sound; ds@1952: } ds@1952: ds@1952: void MenuManager::OnSourceModLevelChange(const char *mapName) ds@1952: { ds@1952: if (m_SelectSound.size() > 0) ds@1952: { ds@1952: enginesound->PrecacheSound(m_SelectSound.c_str(), true); ds@1952: } ds@1952: if (m_ExitBackSound.size() > 0) ds@1952: { ds@1952: enginesound->PrecacheSound(m_ExitBackSound.c_str(), true); ds@1952: } ds@1952: if (m_ExitSound.size() > 0) ds@1952: { ds@1952: enginesound->PrecacheSound(m_ExitSound.c_str(), true); ds@1952: } ds@1952: } ds@1952: ds@1952: void MenuManager::CancelMenu(IBaseMenu *menu) ds@1952: { ds@1952: if (s_VoteHandler.GetCurrentMenu() == menu ds@1952: && !s_VoteHandler.IsCancelling()) ds@1952: { ds@1952: s_VoteHandler.CancelVoting(); ds@1952: return; ds@1952: } ds@1952: ds@1952: menu->Cancel(); ds@1952: } ds@1952: ds@1952: bool MenuManager::StartVote(IBaseMenu *menu, unsigned int num_clients, int clients[], unsigned int max_time, unsigned int flags) ds@1952: { ds@1952: return s_VoteHandler.StartVote(menu, num_clients, clients, max_time, flags); ds@1952: } ds@1952: ds@1952: bool MenuManager::IsVoteInProgress() ds@1952: { ds@1952: return s_VoteHandler.IsVoteInProgress(); ds@1952: } ds@1952: ds@1952: void MenuManager::CancelVoting() ds@1952: { ds@1952: s_VoteHandler.CancelVoting(); ds@1952: } ds@1952: ds@1952: unsigned int MenuManager::GetRemainingVoteDelay() ds@1952: { ds@1952: return s_VoteHandler.GetRemainingVoteDelay(); ds@1952: }