251cced1f8
Various minor things done to project files Updated sample extension project file and updated makefile to the new unified version (more changes likely on the way) Updated regex project file and makefile --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401971
567 lines
12 KiB
C++
567 lines
12 KiB
C++
/**
|
|
* vim: set ts=4 :
|
|
* =============================================================================
|
|
* SourceMod
|
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
|
* =============================================================================
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
* Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* As a special exception, AlliedModders LLC gives you permission to link the
|
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
* this exception to all derivative works. AlliedModders LLC defines further
|
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
* or <http://www.sourcemod.net/license.php>.
|
|
*
|
|
* Version: $Id$
|
|
*/
|
|
|
|
#include "MenuStyle_Radio.h"
|
|
#include "sm_stringutil.h"
|
|
#include "UserMessages.h"
|
|
#include "GameConfigs.h"
|
|
#include "PlayerManager.h"
|
|
#if defined MENU_DEBUG
|
|
#include "Logger.h"
|
|
#endif
|
|
|
|
extern const char *g_RadioNumTable[];
|
|
CRadioStyle g_RadioMenuStyle;
|
|
int g_ShowMenuId = -1;
|
|
bool g_bRadioInit = false;
|
|
unsigned int g_RadioMenuTimeout = 0;
|
|
|
|
CRadioStyle::CRadioStyle()
|
|
{
|
|
m_players = new CRadioMenuPlayer[256+1];
|
|
for (size_t i = 0; i < 256+1; i++)
|
|
{
|
|
m_players[i].Radio_SetIndex(i);
|
|
}
|
|
}
|
|
|
|
void CRadioStyle::OnSourceModAllInitialized()
|
|
{
|
|
g_Players.AddClientListener(this);
|
|
}
|
|
|
|
void CRadioStyle::OnSourceModLevelChange(const char *mapName)
|
|
{
|
|
if (g_bRadioInit)
|
|
{
|
|
return;
|
|
}
|
|
|
|
g_bRadioInit = true;
|
|
const char *msg = g_pGameConf->GetKeyValue("HudRadioMenuMsg");
|
|
if (!msg || msg[0] == '\0')
|
|
{
|
|
return;
|
|
}
|
|
|
|
g_ShowMenuId = g_UserMsgs.GetMessageIndex(msg);
|
|
|
|
if (!IsSupported())
|
|
{
|
|
return;
|
|
}
|
|
|
|
const char *val = g_pGameConf->GetKeyValue("RadioMenuTimeout");
|
|
if (val != NULL)
|
|
{
|
|
g_RadioMenuTimeout = atoi(val);
|
|
}
|
|
else
|
|
{
|
|
g_RadioMenuTimeout = 0;
|
|
}
|
|
|
|
g_Menus.AddStyle(this);
|
|
g_Menus.SetDefaultStyle(this);
|
|
|
|
g_UserMsgs.HookUserMessage(g_ShowMenuId, this, false);
|
|
}
|
|
|
|
void CRadioStyle::OnSourceModShutdown()
|
|
{
|
|
g_Players.RemoveClientListener(this);
|
|
g_UserMsgs.UnhookUserMessage(g_ShowMenuId, this, false);
|
|
|
|
while (!m_FreeDisplays.empty())
|
|
{
|
|
delete m_FreeDisplays.front();
|
|
m_FreeDisplays.pop();
|
|
}
|
|
}
|
|
|
|
bool CRadioStyle::IsSupported()
|
|
{
|
|
return (g_ShowMenuId != -1);
|
|
}
|
|
|
|
bool CRadioStyle::OnClientCommand(int client, const char *cmdname, const CCommand &cmd)
|
|
{
|
|
if (strcmp(cmdname, "menuselect") == 0)
|
|
{
|
|
if (!m_players[client].bInMenu)
|
|
{
|
|
m_players[client].bInExternMenu = false;
|
|
return false;
|
|
}
|
|
|
|
int arg = atoi(cmd.Arg(1));
|
|
ClientPressedKey(client, arg);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static unsigned int g_last_holdtime = 0;
|
|
static unsigned int g_last_client_count = 0;
|
|
static int g_last_clients[256];
|
|
|
|
void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
|
|
{
|
|
int count = pFilter->GetRecipientCount();
|
|
bf_read br(bf->GetBasePointer(), 3);
|
|
|
|
br.ReadWord();
|
|
int c = br.ReadChar();
|
|
|
|
g_last_holdtime = (c == -1) ? 0 : (unsigned)c;
|
|
|
|
for (int i=0; i<count; i++)
|
|
{
|
|
g_last_clients[g_last_client_count++] = pFilter->GetRecipientIndex(i);
|
|
}
|
|
}
|
|
|
|
void CRadioStyle::OnUserMessageSent(int msg_id)
|
|
{
|
|
for (unsigned int i=0; i<g_last_client_count; i++)
|
|
{
|
|
int client = g_last_clients[i];
|
|
#if defined MENU_DEBUG
|
|
g_Logger.LogMessage("[SM_MENU] CRadioStyle got ShowMenu (client %d) (bInMenu %d)",
|
|
client,
|
|
m_players[client].bInExternMenu);
|
|
#endif
|
|
if (m_players[client].bInMenu)
|
|
{
|
|
_CancelClientMenu(client, MenuCancel_Interrupted, true);
|
|
}
|
|
m_players[client].bInExternMenu = true;
|
|
m_players[client].menuHoldTime = g_last_holdtime;
|
|
}
|
|
g_last_client_count = 0;
|
|
}
|
|
|
|
void CRadioStyle::SendDisplay(int client, IMenuPanel *display)
|
|
{
|
|
CRadioDisplay *rDisplay = (CRadioDisplay *)display;
|
|
rDisplay->SendRawDisplay(client, m_players[client].menuHoldTime);
|
|
}
|
|
|
|
IMenuPanel *CRadioStyle::CreatePanel()
|
|
{
|
|
return g_RadioMenuStyle.MakeRadioDisplay();
|
|
}
|
|
|
|
IBaseMenu *CRadioStyle::CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner)
|
|
{
|
|
return new CRadioMenu(pHandler, pOwner);
|
|
}
|
|
|
|
unsigned int CRadioStyle::GetMaxPageItems()
|
|
{
|
|
return 10;
|
|
}
|
|
|
|
const char *CRadioStyle::GetStyleName()
|
|
{
|
|
return "radio";
|
|
}
|
|
|
|
CBaseMenuPlayer *CRadioStyle::GetMenuPlayer(int client)
|
|
{
|
|
return &m_players[client];
|
|
}
|
|
|
|
CRadioDisplay *CRadioStyle::MakeRadioDisplay(CRadioMenu *menu)
|
|
{
|
|
CRadioDisplay *display;
|
|
if (m_FreeDisplays.empty())
|
|
{
|
|
display = new CRadioDisplay();
|
|
}
|
|
else
|
|
{
|
|
display = m_FreeDisplays.front();
|
|
m_FreeDisplays.pop();
|
|
display->Reset();
|
|
}
|
|
return display;
|
|
}
|
|
|
|
IMenuPanel *CRadioStyle::MakeRadioDisplay(const char *str, int keys)
|
|
{
|
|
CRadioDisplay *pPanel = MakeRadioDisplay(NULL);
|
|
|
|
pPanel->DirectSet(str, keys);
|
|
|
|
return pPanel;
|
|
}
|
|
|
|
void CRadioStyle::FreeRadioDisplay(CRadioDisplay *display)
|
|
{
|
|
m_FreeDisplays.push(display);
|
|
}
|
|
|
|
CRadioMenuPlayer *CRadioStyle::GetRadioMenuPlayer(int client)
|
|
{
|
|
return &m_players[client];
|
|
}
|
|
|
|
void CRadioStyle::ProcessWatchList()
|
|
{
|
|
if (!g_RadioMenuTimeout)
|
|
{
|
|
BaseMenuStyle::ProcessWatchList();
|
|
return;
|
|
}
|
|
|
|
BaseMenuStyle::ProcessWatchList();
|
|
|
|
CRadioMenuPlayer *pPlayer;
|
|
unsigned int max_clients = g_Players.GetMaxClients();
|
|
for (unsigned int i = 1; i <= max_clients; i++)
|
|
{
|
|
pPlayer = GetRadioMenuPlayer(i);
|
|
if (!pPlayer->bInMenu || pPlayer->bInExternMenu)
|
|
{
|
|
continue;
|
|
}
|
|
if (pPlayer->Radio_NeedsRefresh())
|
|
{
|
|
pPlayer->Radio_Refresh();
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned int CRadioStyle::GetApproxMemUsage()
|
|
{
|
|
return sizeof(CRadioStyle) + (sizeof(CRadioMenuPlayer) * 257);
|
|
}
|
|
|
|
CRadioDisplay::CRadioDisplay()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
CRadioDisplay::CRadioDisplay(CRadioMenu *menu)
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
bool CRadioDisplay::DrawRawLine(const char *rawline)
|
|
{
|
|
m_BufferText.append(rawline);
|
|
m_BufferText.append("\n");
|
|
return true;
|
|
}
|
|
|
|
void CRadioDisplay::Reset()
|
|
{
|
|
m_BufferText.assign("");
|
|
m_Title.assign("");
|
|
m_NextPos = 1;
|
|
keys = 0;
|
|
}
|
|
|
|
void CRadioDisplay::DirectSet(const char *str, int keymap)
|
|
{
|
|
m_Title.clear();
|
|
m_BufferText.assign(str);
|
|
keys = keymap;
|
|
}
|
|
|
|
unsigned int CRadioDisplay::GetCurrentKey()
|
|
{
|
|
return m_NextPos;
|
|
}
|
|
|
|
bool CRadioDisplay::SetCurrentKey(unsigned int key)
|
|
{
|
|
if (key < m_NextPos || m_NextPos > 10)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_NextPos = key;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CRadioDisplay::SendDisplay(int client, IMenuHandler *handler, unsigned int time)
|
|
{
|
|
return g_RadioMenuStyle.DoClientMenu(client, this, handler, time);
|
|
}
|
|
|
|
bool CRadioDisplay::SetExtOption(MenuOption option, const void *valuePtr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
IMenuStyle *CRadioDisplay::GetParentStyle()
|
|
{
|
|
return &g_RadioMenuStyle;
|
|
}
|
|
|
|
void CRadioDisplay::DrawTitle(const char *text, bool onlyIfEmpty/* =false */)
|
|
{
|
|
if (m_Title.size() != 0 && onlyIfEmpty)
|
|
{
|
|
return;
|
|
}
|
|
m_Title.assign(text);
|
|
}
|
|
|
|
unsigned int CRadioDisplay::DrawItem(const ItemDrawInfo &item)
|
|
{
|
|
if (m_NextPos > 10 || !CanDrawItem(item.style))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (item.style & ITEMDRAW_RAWLINE)
|
|
{
|
|
if (item.style & ITEMDRAW_SPACER)
|
|
{
|
|
m_BufferText.append(" \n");
|
|
} else {
|
|
m_BufferText.append(item.display);
|
|
m_BufferText.append("\n");
|
|
}
|
|
return 0;
|
|
} else if (item.style & ITEMDRAW_SPACER) {
|
|
m_BufferText.append(" \n");
|
|
return m_NextPos++;
|
|
} else if (item.style & ITEMDRAW_NOTEXT) {
|
|
return m_NextPos++;
|
|
}
|
|
|
|
if (item.style & ITEMDRAW_DISABLED)
|
|
{
|
|
m_BufferText.append(g_RadioNumTable[m_NextPos]);
|
|
m_BufferText.append(item.display);
|
|
m_BufferText.append("\n");
|
|
} else {
|
|
m_BufferText.append("->");
|
|
m_BufferText.append(g_RadioNumTable[m_NextPos]);
|
|
m_BufferText.append(item.display);
|
|
m_BufferText.append("\n");
|
|
keys |= (1<<(m_NextPos-1));
|
|
}
|
|
|
|
return m_NextPos++;
|
|
}
|
|
|
|
bool CRadioDisplay::CanDrawItem(unsigned int drawFlags)
|
|
{
|
|
if ((drawFlags & ITEMDRAW_IGNORE) == ITEMDRAW_IGNORE)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ((drawFlags & ITEMDRAW_DISABLED) && (drawFlags & ITEMDRAW_CONTROL))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CRadioDisplay::SendRawDisplay(int client, unsigned int time)
|
|
{
|
|
int _sel_keys = (keys == 0) ? (1<<9) : keys;
|
|
CRadioMenuPlayer *pPlayer = g_RadioMenuStyle.GetRadioMenuPlayer(client);
|
|
pPlayer->Radio_Init(_sel_keys, m_Title.c_str(), m_BufferText.c_str());
|
|
pPlayer->Radio_Refresh();
|
|
}
|
|
|
|
void CRadioMenuPlayer::Radio_SetIndex(unsigned int index)
|
|
{
|
|
m_index = index;
|
|
}
|
|
|
|
bool CRadioMenuPlayer::Radio_NeedsRefresh()
|
|
{
|
|
return (gpGlobals->curtime - display_last_refresh >= g_RadioMenuTimeout);
|
|
}
|
|
|
|
void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text)
|
|
{
|
|
if (title[0] != '\0')
|
|
{
|
|
display_len = UTIL_Format(display_pkt,
|
|
sizeof(display_pkt),
|
|
"%s\n%s",
|
|
title,
|
|
text);
|
|
}
|
|
else
|
|
{
|
|
display_len = UTIL_Format(display_pkt,
|
|
sizeof(display_pkt),
|
|
"%s",
|
|
text);
|
|
}
|
|
display_keys = keys;
|
|
}
|
|
|
|
void CRadioMenuPlayer::Radio_Refresh()
|
|
{
|
|
cell_t players[1] = {m_index};
|
|
char *ptr = display_pkt;
|
|
char save = 0;
|
|
size_t len = display_len;
|
|
unsigned int time;
|
|
|
|
/* Compute the new time */
|
|
if (menuHoldTime == 0)
|
|
{
|
|
time = 0;
|
|
}
|
|
else
|
|
{
|
|
time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
|
|
}
|
|
|
|
while (true)
|
|
{
|
|
if (len > 240)
|
|
{
|
|
save = ptr[240];
|
|
ptr[240] = '\0';
|
|
}
|
|
bf_write *buffer = g_UserMsgs.StartMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
|
|
buffer->WriteWord(display_keys);
|
|
buffer->WriteChar(time ? time : -1);
|
|
buffer->WriteByte( (len > 240) ? 1 : 0 );
|
|
buffer->WriteString(ptr);
|
|
g_UserMsgs.EndMessage();
|
|
if (len > 240)
|
|
{
|
|
ptr[240] = save;
|
|
ptr = &ptr[240];
|
|
len -= 240;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
display_last_refresh = gpGlobals->curtime;
|
|
}
|
|
|
|
int CRadioDisplay::GetAmountRemaining()
|
|
{
|
|
size_t amt = m_Title.size() + 1 + m_BufferText.size();
|
|
if (amt >= 511)
|
|
{
|
|
return 0;
|
|
}
|
|
return (int)(511 - amt);
|
|
}
|
|
|
|
void CRadioDisplay::DeleteThis()
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
bool CRadioDisplay::SetSelectableKeys(unsigned int keymap)
|
|
{
|
|
keys = (signed)keymap;
|
|
return true;
|
|
}
|
|
|
|
unsigned int CRadioDisplay::GetApproxMemUsage()
|
|
{
|
|
return sizeof(CRadioDisplay)
|
|
+ m_BufferText.size()
|
|
+ m_Title.size();
|
|
}
|
|
|
|
CRadioMenu::CRadioMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) :
|
|
CBaseMenu(pHandler, &g_RadioMenuStyle, pOwner)
|
|
{
|
|
}
|
|
|
|
bool CRadioMenu::SetExtOption(MenuOption option, const void *valuePtr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
IMenuPanel *CRadioMenu::CreatePanel()
|
|
{
|
|
return g_RadioMenuStyle.MakeRadioDisplay(this);
|
|
}
|
|
|
|
bool CRadioMenu::Display(int client, unsigned int time, IMenuHandler *alt_handler)
|
|
{
|
|
return DisplayAtItem(client, time, 0, alt_handler);
|
|
}
|
|
|
|
bool CRadioMenu::DisplayAtItem(int client,
|
|
unsigned int time,
|
|
unsigned int start_item,
|
|
IMenuHandler *alt_handler)
|
|
{
|
|
#if defined MENU_DEBUG
|
|
g_Logger.LogMessage("[SM_MENU] CRadioMenu::Display(%p) (client %d) (time %d)",
|
|
this,
|
|
client,
|
|
time);
|
|
#endif
|
|
if (m_bCancelling)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return g_RadioMenuStyle.DoClientMenu(client,
|
|
this,
|
|
start_item,
|
|
alt_handler ? alt_handler : m_pHandler,
|
|
time);
|
|
}
|
|
|
|
void CRadioMenu::Cancel_Finally()
|
|
{
|
|
g_RadioMenuStyle.CancelMenu(this);
|
|
}
|
|
|
|
unsigned int CRadioMenu::GetApproxMemUsage()
|
|
{
|
|
return sizeof(CRadioMenu) + GetBaseMemUsage();
|
|
}
|
|
|
|
const char *g_RadioNumTable[11] =
|
|
{
|
|
"0. ", "1. ", "2. ", "3. ", "4. ", "5. ", "6. ", "7. ", "8. ", "9. ", "0. "
|
|
};
|