dvander@780: /** dvander@780: * vim: set ts=4 : ds@1330: * ============================================================================= dvander@1231: * SourceMod ds@1947: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. ds@1330: * ============================================================================= dvander@780: * 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@780: * dvander@780: * Version: $Id$ dvander@780: */ dvander@780: dvander@780: #include "MenuStyle_Radio.h" dvander@780: #include "sm_stringutil.h" dvander@780: #include "UserMessages.h" dvander@780: #include "GameConfigs.h" dvander@846: #include "PlayerManager.h" dvander@970: #if defined MENU_DEBUG dvander@970: #include "Logger.h" dvander@970: #endif dvander@780: dvander@780: extern const char *g_RadioNumTable[]; dvander@780: CRadioStyle g_RadioMenuStyle; dvander@780: int g_ShowMenuId = -1; dvander@785: bool g_bRadioInit = false; dvander@1695: unsigned int g_RadioMenuTimeout = 0; dvander@780: dvander@1695: CRadioStyle::CRadioStyle() dvander@780: { dvander@1695: m_players = new CRadioMenuPlayer[256+1]; dvander@1695: for (size_t i = 0; i < 256+1; i++) dvander@1695: { dvander@1695: m_players[i].Radio_SetIndex(i); dvander@1695: } dvander@780: } dvander@780: dvander@846: void CRadioStyle::OnSourceModAllInitialized() dvander@846: { dvander@846: g_Players.AddClientListener(this); dvander@846: } dvander@846: dvander@785: void CRadioStyle::OnSourceModLevelChange(const char *mapName) dvander@780: { dvander@785: if (g_bRadioInit) dvander@785: { dvander@785: return; dvander@785: } dvander@785: dvander@785: g_bRadioInit = true; dvander@780: const char *msg = g_pGameConf->GetKeyValue("HudRadioMenuMsg"); dvander@780: if (!msg || msg[0] == '\0') dvander@780: { dvander@780: return; dvander@780: } dvander@780: dvander@780: g_ShowMenuId = g_UserMsgs.GetMessageIndex(msg); dvander@780: dvander@780: if (!IsSupported()) dvander@780: { dvander@780: return; dvander@780: } dvander@780: dvander@1695: const char *val = g_pGameConf->GetKeyValue("RadioMenuTimeout"); dvander@1695: if (val != NULL) dvander@1695: { dvander@1695: g_RadioMenuTimeout = atoi(val); dvander@1695: } dvander@1695: else dvander@1695: { dvander@1695: g_RadioMenuTimeout = 0; dvander@1695: } dvander@1695: dvander@780: g_Menus.AddStyle(this); dvander@780: g_Menus.SetDefaultStyle(this); dvander@780: dvander@780: g_UserMsgs.HookUserMessage(g_ShowMenuId, this, false); dvander@780: } dvander@780: dvander@780: void CRadioStyle::OnSourceModShutdown() dvander@780: { dvander@846: g_Players.RemoveClientListener(this); dvander@780: g_UserMsgs.UnhookUserMessage(g_ShowMenuId, this, false); dvander@790: dvander@790: while (!m_FreeDisplays.empty()) dvander@790: { dvander@790: delete m_FreeDisplays.front(); dvander@790: m_FreeDisplays.pop(); dvander@790: } dvander@780: } dvander@780: dvander@780: bool CRadioStyle::IsSupported() dvander@780: { dvander@780: return (g_ShowMenuId != -1); dvander@780: } dvander@780: faluco@1541: bool CRadioStyle::OnClientCommand(int client, const char *cmdname, const CCommand &cmd) dvander@780: { faluco@1541: if (strcmp(cmdname, "menuselect") == 0) dvander@780: { dvander@780: if (!m_players[client].bInMenu) dvander@780: { dvander@1838: m_players[client].bInExternMenu = false; dvander@780: return false; dvander@780: } dvander@785: faluco@1541: int arg = atoi(cmd.Arg(1)); dvander@780: ClientPressedKey(client, arg); dvander@785: return true; dvander@780: } dvander@780: dvander@780: return false; dvander@780: } dvander@780: dvander@780: static unsigned int g_last_holdtime = 0; dvander@780: static unsigned int g_last_client_count = 0; dvander@780: static int g_last_clients[256]; dvander@780: dvander@780: void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter) dvander@780: { dvander@780: int count = pFilter->GetRecipientCount(); dvander@1838: bf_read br(bf->GetBasePointer(), 3); dvander@780: dvander@780: br.ReadWord(); dvander@780: int c = br.ReadChar(); dvander@780: dvander@780: g_last_holdtime = (c == -1) ? 0 : (unsigned)c; dvander@780: dvander@780: for (int i=0; iGetRecipientIndex(i); dvander@780: } dvander@780: } dvander@780: dvander@780: void CRadioStyle::OnUserMessageSent(int msg_id) dvander@780: { dvander@780: for (unsigned int i=0; iSendRawDisplay(client, m_players[client].menuHoldTime); dvander@780: } dvander@780: dvander@787: IMenuPanel *CRadioStyle::CreatePanel() dvander@780: { dvander@790: return g_RadioMenuStyle.MakeRadioDisplay(); dvander@780: } dvander@780: dvander@790: IBaseMenu *CRadioStyle::CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) dvander@780: { dvander@790: return new CRadioMenu(pHandler, pOwner); dvander@780: } dvander@780: dvander@780: unsigned int CRadioStyle::GetMaxPageItems() dvander@780: { dvander@780: return 10; dvander@780: } dvander@780: dvander@780: const char *CRadioStyle::GetStyleName() dvander@780: { dvander@780: return "radio"; dvander@780: } dvander@780: dvander@780: CBaseMenuPlayer *CRadioStyle::GetMenuPlayer(int client) dvander@780: { dvander@780: return &m_players[client]; dvander@780: } dvander@780: dvander@790: CRadioDisplay *CRadioStyle::MakeRadioDisplay(CRadioMenu *menu) dvander@790: { dvander@790: CRadioDisplay *display; dvander@790: if (m_FreeDisplays.empty()) dvander@790: { dvander@790: display = new CRadioDisplay(); dvander@1705: } dvander@1705: else dvander@1705: { dvander@790: display = m_FreeDisplays.front(); dvander@790: m_FreeDisplays.pop(); dvander@790: display->Reset(); dvander@790: } dvander@790: return display; dvander@790: } dvander@790: dvander@1705: IMenuPanel *CRadioStyle::MakeRadioDisplay(const char *str, int keys) dvander@1705: { dvander@1705: CRadioDisplay *pPanel = MakeRadioDisplay(NULL); dvander@1705: dvander@1705: pPanel->DirectSet(str, keys); dvander@1705: dvander@1705: return pPanel; dvander@1705: } dvander@1705: dvander@790: void CRadioStyle::FreeRadioDisplay(CRadioDisplay *display) dvander@790: { dvander@790: m_FreeDisplays.push(display); dvander@790: } dvander@790: dvander@1695: CRadioMenuPlayer *CRadioStyle::GetRadioMenuPlayer(int client) dvander@1695: { dvander@1695: return &m_players[client]; dvander@1695: } dvander@1695: dvander@1695: void CRadioStyle::ProcessWatchList() dvander@1695: { dvander@1695: if (!g_RadioMenuTimeout) dvander@1695: { dvander@1695: BaseMenuStyle::ProcessWatchList(); dvander@1695: return; dvander@1695: } dvander@1695: dvander@1695: BaseMenuStyle::ProcessWatchList(); dvander@1695: dvander@1695: CRadioMenuPlayer *pPlayer; dvander@1695: unsigned int max_clients = g_Players.GetMaxClients(); dvander@1695: for (unsigned int i = 1; i <= max_clients; i++) dvander@1695: { dvander@1695: pPlayer = GetRadioMenuPlayer(i); dvander@1695: if (!pPlayer->bInMenu || pPlayer->bInExternMenu) dvander@1695: { dvander@1695: continue; dvander@1695: } dvander@1695: if (pPlayer->Radio_NeedsRefresh()) dvander@1695: { dvander@1695: pPlayer->Radio_Refresh(); dvander@1695: } dvander@1695: } dvander@1695: } dvander@1695: dvander@1766: unsigned int CRadioStyle::GetApproxMemUsage() dvander@1766: { dvander@1766: return sizeof(CRadioStyle) + (sizeof(CRadioMenuPlayer) * 257); dvander@1766: } dvander@1766: dvander@780: CRadioDisplay::CRadioDisplay() dvander@780: { dvander@780: Reset(); dvander@780: } dvander@780: dvander@780: CRadioDisplay::CRadioDisplay(CRadioMenu *menu) dvander@780: { dvander@780: Reset(); dvander@780: } dvander@780: dvander@780: bool CRadioDisplay::DrawRawLine(const char *rawline) dvander@780: { dvander@780: m_BufferText.append(rawline); dvander@780: m_BufferText.append("\n"); dvander@780: return true; dvander@780: } dvander@780: dvander@780: void CRadioDisplay::Reset() dvander@780: { dvander@780: m_BufferText.assign(""); dvander@780: m_Title.assign(""); dvander@780: m_NextPos = 1; dvander@785: keys = 0; dvander@780: } dvander@780: dvander@1705: void CRadioDisplay::DirectSet(const char *str, int keymap) dvander@1705: { dvander@1705: m_Title.clear(); dvander@1705: m_BufferText.assign(str); dvander@1705: keys = keymap; dvander@1705: } dvander@1705: dvander@840: unsigned int CRadioDisplay::GetCurrentKey() dvander@840: { dvander@840: return m_NextPos; dvander@840: } dvander@840: dvander@840: bool CRadioDisplay::SetCurrentKey(unsigned int key) dvander@840: { dvander@840: if (key < m_NextPos || m_NextPos > 10) dvander@840: { dvander@840: return false; dvander@840: } dvander@840: dvander@840: m_NextPos = key; dvander@840: dvander@840: return true; dvander@840: } dvander@840: dvander@780: bool CRadioDisplay::SendDisplay(int client, IMenuHandler *handler, unsigned int time) dvander@780: { dvander@780: return g_RadioMenuStyle.DoClientMenu(client, this, handler, time); dvander@780: } dvander@780: dvander@780: bool CRadioDisplay::SetExtOption(MenuOption option, const void *valuePtr) dvander@780: { dvander@780: return false; dvander@780: } dvander@780: dvander@780: IMenuStyle *CRadioDisplay::GetParentStyle() dvander@780: { dvander@780: return &g_RadioMenuStyle; dvander@780: } dvander@780: dvander@780: void CRadioDisplay::DrawTitle(const char *text, bool onlyIfEmpty/* =false */) dvander@780: { dvander@780: if (m_Title.size() != 0 && onlyIfEmpty) dvander@780: { dvander@780: return; dvander@780: } dvander@780: m_Title.assign(text); dvander@780: } dvander@780: dvander@780: unsigned int CRadioDisplay::DrawItem(const ItemDrawInfo &item) dvander@780: { dvander@780: if (m_NextPos > 10 || !CanDrawItem(item.style)) dvander@780: { dvander@780: return 0; dvander@780: } dvander@780: dvander@780: if (item.style & ITEMDRAW_RAWLINE) dvander@780: { dvander@780: if (item.style & ITEMDRAW_SPACER) dvander@780: { dvander@785: m_BufferText.append(" \n"); dvander@780: } else { dvander@780: m_BufferText.append(item.display); dvander@780: m_BufferText.append("\n"); dvander@780: } dvander@780: return 0; dvander@780: } else if (item.style & ITEMDRAW_SPACER) { dvander@785: m_BufferText.append(" \n"); dvander@785: return m_NextPos++; dvander@785: } else if (item.style & ITEMDRAW_NOTEXT) { dvander@780: return m_NextPos++; dvander@780: } dvander@780: dvander@780: if (item.style & ITEMDRAW_DISABLED) dvander@780: { dvander@780: m_BufferText.append(g_RadioNumTable[m_NextPos]); dvander@780: m_BufferText.append(item.display); dvander@780: m_BufferText.append("\n"); dvander@780: } else { dvander@785: m_BufferText.append("->"); dvander@785: m_BufferText.append(g_RadioNumTable[m_NextPos]); dvander@780: m_BufferText.append(item.display); dvander@780: m_BufferText.append("\n"); dvander@780: keys |= (1<<(m_NextPos-1)); dvander@780: } dvander@780: dvander@780: return m_NextPos++; dvander@780: } dvander@780: dvander@780: bool CRadioDisplay::CanDrawItem(unsigned int drawFlags) dvander@780: { dvander@780: if ((drawFlags & ITEMDRAW_IGNORE) == ITEMDRAW_IGNORE) dvander@780: { dvander@780: return false; dvander@780: } dvander@780: dvander@785: if ((drawFlags & ITEMDRAW_DISABLED) && (drawFlags & ITEMDRAW_CONTROL)) dvander@785: { dvander@785: return false; dvander@785: } dvander@785: dvander@780: return true; dvander@780: } dvander@780: dvander@780: void CRadioDisplay::SendRawDisplay(int client, unsigned int time) dvander@780: { dvander@1695: int _sel_keys = (keys == 0) ? (1<<9) : keys; dvander@1695: CRadioMenuPlayer *pPlayer = g_RadioMenuStyle.GetRadioMenuPlayer(client); dvander@1695: pPlayer->Radio_Init(_sel_keys, m_Title.c_str(), m_BufferText.c_str()); dvander@1695: pPlayer->Radio_Refresh(); dvander@1695: } dvander@780: dvander@1695: void CRadioMenuPlayer::Radio_SetIndex(unsigned int index) dvander@1695: { dvander@1695: m_index = index; dvander@1695: } dvander@1695: dvander@1695: bool CRadioMenuPlayer::Radio_NeedsRefresh() dvander@1695: { dvander@1695: return (gpGlobals->curtime - display_last_refresh >= g_RadioMenuTimeout); dvander@1695: } dvander@780: dvander@1695: void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text) dvander@1695: { dvander@1705: if (title[0] != '\0') dvander@1705: { dvander@1705: display_len = UTIL_Format(display_pkt, dvander@1705: sizeof(display_pkt), dvander@1705: "%s\n%s", dvander@1705: title, dvander@1705: text); dvander@1705: } dvander@1705: else dvander@1705: { dvander@1705: display_len = UTIL_Format(display_pkt, dvander@1705: sizeof(display_pkt), dvander@1705: "%s", dvander@1705: text); dvander@1705: } dvander@1695: display_keys = keys; dvander@1695: } dvander@780: dvander@1695: void CRadioMenuPlayer::Radio_Refresh() dvander@1695: { dvander@1695: cell_t players[1] = {m_index}; dvander@1695: char *ptr = display_pkt; dvander@1695: char save = 0; dvander@1695: size_t len = display_len; dvander@1695: unsigned int time; dvander@819: dvander@1695: /* Compute the new time */ dvander@1695: if (menuHoldTime == 0) dvander@1695: { dvander@1695: time = 0; dvander@1695: } dvander@1695: else dvander@1695: { dvander@1695: time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime); dvander@1695: } dvander@1695: dvander@780: while (true) dvander@780: { dvander@780: if (len > 240) dvander@780: { dvander@780: save = ptr[240]; dvander@780: ptr[240] = '\0'; dvander@780: } dvander@1251: bf_write *buffer = g_UserMsgs.StartMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS); dvander@1695: buffer->WriteWord(display_keys); dvander@780: buffer->WriteChar(time ? time : -1); dvander@780: buffer->WriteByte( (len > 240) ? 1 : 0 ); dvander@780: buffer->WriteString(ptr); dvander@780: g_UserMsgs.EndMessage(); dvander@780: if (len > 240) dvander@780: { dvander@780: ptr[240] = save; dvander@780: ptr = &ptr[240]; dvander@780: len -= 240; dvander@1695: } dvander@1695: else dvander@1695: { dvander@780: break; dvander@780: } dvander@780: } dvander@1695: dvander@1695: display_last_refresh = gpGlobals->curtime; dvander@780: } dvander@780: dvander@1361: int CRadioDisplay::GetAmountRemaining() dvander@1361: { dvander@1361: size_t amt = m_Title.size() + 1 + m_BufferText.size(); dvander@1361: if (amt >= 511) dvander@1361: { dvander@1361: return 0; dvander@1361: } dvander@1361: return (int)(511 - amt); dvander@1361: } dvander@1361: dvander@780: void CRadioDisplay::DeleteThis() dvander@780: { dvander@780: delete this; dvander@780: } dvander@780: dvander@819: bool CRadioDisplay::SetSelectableKeys(unsigned int keymap) dvander@819: { dvander@819: keys = (signed)keymap; dvander@820: return true; dvander@819: } dvander@819: dvander@1766: unsigned int CRadioDisplay::GetApproxMemUsage() dvander@1766: { dvander@1766: return sizeof(CRadioDisplay) dvander@1766: + m_BufferText.size() dvander@1766: + m_Title.size(); dvander@1766: } dvander@1766: dvander@790: CRadioMenu::CRadioMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) : dvander@790: CBaseMenu(pHandler, &g_RadioMenuStyle, pOwner) dvander@780: { dvander@780: } dvander@780: dvander@780: bool CRadioMenu::SetExtOption(MenuOption option, const void *valuePtr) dvander@780: { dvander@780: return false; dvander@780: } dvander@780: dvander@787: IMenuPanel *CRadioMenu::CreatePanel() dvander@780: { dvander@790: return g_RadioMenuStyle.MakeRadioDisplay(this); dvander@780: } dvander@780: dvander@1269: bool CRadioMenu::Display(int client, unsigned int time, IMenuHandler *alt_handler) dvander@780: { dvander@1474: return DisplayAtItem(client, time, 0, alt_handler); dvander@1474: } dvander@1474: dvander@1474: bool CRadioMenu::DisplayAtItem(int client, dvander@1474: unsigned int time, dvander@1474: unsigned int start_item, dvander@1474: IMenuHandler *alt_handler) dvander@1474: { dvander@970: #if defined MENU_DEBUG dvander@970: g_Logger.LogMessage("[SM_MENU] CRadioMenu::Display(%p) (client %d) (time %d)", dvander@970: this, dvander@970: client, dvander@970: time); dvander@970: #endif dvander@877: if (m_bCancelling) dvander@877: { dvander@877: return false; dvander@877: } dvander@877: dvander@1474: return g_RadioMenuStyle.DoClientMenu(client, dvander@1474: this, dvander@1474: start_item, dvander@1474: alt_handler ? alt_handler : m_pHandler, dvander@1474: time); dvander@877: } dvander@877: dvander@780: void CRadioMenu::Cancel_Finally() dvander@780: { dvander@780: g_RadioMenuStyle.CancelMenu(this); dvander@780: } dvander@780: dvander@1766: unsigned int CRadioMenu::GetApproxMemUsage() dvander@1766: { dvander@1766: return sizeof(CRadioMenu) + GetBaseMemUsage(); dvander@1766: } dvander@1766: dvander@780: const char *g_RadioNumTable[11] = dvander@780: { dvander@785: "0. ", "1. ", "2. ", "3. ", "4. ", "5. ", "6. ", "7. ", "8. ", "9. ", "0. " dvander@780: };