core/MenuStyle_Radio.cpp
author David Anderson <dvander@alliedmods.net>
Tue Dec 04 15:58:07 2007 +0000 (2007-12-04)
changeset 1764 e4f24e9789fd
parent 1705 ce47e6d42853
child 1766 d30c252089be
permissions -rw-r--r--
- removed ancient bcompat shim for translations/core.cfg file
- fixed msvc8 whining about BfReadString
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "MenuStyle_Radio.h"
    33 #include "sm_stringutil.h"
    34 #include "UserMessages.h"
    35 #include "GameConfigs.h"
    36 #include "PlayerManager.h"
    37 #if defined MENU_DEBUG
    38 #include "Logger.h"
    39 #endif
    40 
    41 extern const char *g_RadioNumTable[];
    42 CRadioStyle g_RadioMenuStyle;
    43 int g_ShowMenuId = -1;
    44 bool g_bRadioInit = false;
    45 unsigned int g_RadioMenuTimeout = 0;
    46 
    47 CRadioStyle::CRadioStyle()
    48 {
    49 	m_players = new CRadioMenuPlayer[256+1];
    50 	for (size_t i = 0; i < 256+1; i++)
    51 	{
    52 		m_players[i].Radio_SetIndex(i);
    53 	}
    54 }
    55 
    56 void CRadioStyle::OnSourceModAllInitialized()
    57 {
    58 	g_Players.AddClientListener(this);
    59 }
    60 
    61 void CRadioStyle::OnSourceModLevelChange(const char *mapName)
    62 {
    63 	if (g_bRadioInit)
    64 	{
    65 		return;
    66 	}
    67 
    68 	g_bRadioInit = true;
    69 	const char *msg = g_pGameConf->GetKeyValue("HudRadioMenuMsg");
    70 	if (!msg || msg[0] == '\0')
    71 	{
    72 		return;
    73 	}
    74 
    75 	g_ShowMenuId = g_UserMsgs.GetMessageIndex(msg);
    76 
    77 	if (!IsSupported())
    78 	{
    79 		return;
    80 	}
    81 
    82 	const char *val = g_pGameConf->GetKeyValue("RadioMenuTimeout");
    83 	if (val != NULL)
    84 	{
    85 		g_RadioMenuTimeout = atoi(val);
    86 	}
    87 	else
    88 	{
    89 		g_RadioMenuTimeout = 0;
    90 	}
    91 
    92 	g_Menus.AddStyle(this);
    93 	g_Menus.SetDefaultStyle(this);
    94 
    95 	g_UserMsgs.HookUserMessage(g_ShowMenuId, this, false);
    96 }
    97 
    98 void CRadioStyle::OnSourceModShutdown()
    99 {
   100 	g_Players.RemoveClientListener(this);
   101 	g_UserMsgs.UnhookUserMessage(g_ShowMenuId, this, false);
   102 
   103 	while (!m_FreeDisplays.empty())
   104 	{
   105 		delete m_FreeDisplays.front();
   106 		m_FreeDisplays.pop();
   107 	}
   108 }
   109 
   110 bool CRadioStyle::IsSupported()
   111 {
   112 	return (g_ShowMenuId != -1);
   113 }
   114 
   115 bool CRadioStyle::OnClientCommand(int client, const char *cmdname, const CCommand &cmd)
   116 {
   117 	if (strcmp(cmdname, "menuselect") == 0)
   118 	{
   119 		if (!m_players[client].bInMenu)
   120 		{
   121 			return false;
   122 		}
   123 
   124 		int arg = atoi(cmd.Arg(1));
   125 		ClientPressedKey(client, arg);
   126 		return true;
   127 	}
   128 
   129 	return false;
   130 }
   131 
   132 static unsigned int g_last_holdtime = 0;
   133 static unsigned int g_last_client_count = 0;
   134 static int g_last_clients[256];
   135 
   136 void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFilter)
   137 {
   138 	int count = pFilter->GetRecipientCount();
   139 	bf_read br(bf->GetBasePointer(), 2);
   140 
   141 	br.ReadWord();
   142 	int c = br.ReadChar();
   143 
   144 	g_last_holdtime = (c == -1) ? 0 : (unsigned)c;
   145 
   146 	for (int i=0; i<count; i++)
   147 	{
   148 		g_last_clients[g_last_client_count++] = pFilter->GetRecipientIndex(i);
   149 	}
   150 }
   151 
   152 void CRadioStyle::OnUserMessageSent(int msg_id)
   153 {
   154 	for (unsigned int i=0; i<g_last_client_count; i++)
   155 	{
   156 		int client = g_last_clients[i];
   157 #if defined MENU_DEBUG
   158 		g_Logger.LogMessage("[SM_MENU] CRadioStyle got ShowMenu (client %d) (bInMenu %d)",
   159 			client,
   160 			m_players[client].bInExternMenu);
   161 #endif
   162 		if (m_players[client].bInMenu)
   163 		{
   164 			_CancelClientMenu(client, MenuCancel_Interrupted, true);
   165 		}
   166 		m_players[client].bInExternMenu = true;
   167 		m_players[client].menuHoldTime = g_last_holdtime;
   168 	}
   169 	g_last_client_count = 0;
   170 }
   171 
   172 void CRadioStyle::SendDisplay(int client, IMenuPanel *display)
   173 {
   174 	CRadioDisplay *rDisplay = (CRadioDisplay *)display;
   175 	rDisplay->SendRawDisplay(client, m_players[client].menuHoldTime);
   176 }
   177 
   178 IMenuPanel *CRadioStyle::CreatePanel()
   179 {
   180 	return g_RadioMenuStyle.MakeRadioDisplay();
   181 }
   182 
   183 IBaseMenu *CRadioStyle::CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner)
   184 {
   185 	return new CRadioMenu(pHandler, pOwner);
   186 }
   187 
   188 unsigned int CRadioStyle::GetMaxPageItems()
   189 {
   190 	return 10;
   191 }
   192 
   193 const char *CRadioStyle::GetStyleName()
   194 {
   195 	return "radio";
   196 }
   197 
   198 CBaseMenuPlayer *CRadioStyle::GetMenuPlayer(int client)
   199 {
   200 	return &m_players[client];
   201 }
   202 
   203 CRadioDisplay *CRadioStyle::MakeRadioDisplay(CRadioMenu *menu)
   204 {
   205 	CRadioDisplay *display;
   206 	if (m_FreeDisplays.empty())
   207 	{
   208 		display = new CRadioDisplay();
   209 	}
   210 	else
   211 	{
   212 		display = m_FreeDisplays.front();
   213 		m_FreeDisplays.pop();
   214 		display->Reset();
   215 	}
   216 	return display;
   217 }
   218 
   219 IMenuPanel *CRadioStyle::MakeRadioDisplay(const char *str, int keys)
   220 {
   221 	CRadioDisplay *pPanel = MakeRadioDisplay(NULL);
   222 
   223 	pPanel->DirectSet(str, keys);
   224 
   225 	return pPanel;
   226 }
   227 
   228 void CRadioStyle::FreeRadioDisplay(CRadioDisplay *display)
   229 {
   230 	m_FreeDisplays.push(display);
   231 }
   232 
   233 CRadioMenuPlayer *CRadioStyle::GetRadioMenuPlayer(int client)
   234 {
   235 	return &m_players[client];
   236 }
   237 
   238 void CRadioStyle::ProcessWatchList()
   239 {
   240 	if (!g_RadioMenuTimeout)
   241 	{
   242 		BaseMenuStyle::ProcessWatchList();
   243 		return;
   244 	}
   245 
   246 	BaseMenuStyle::ProcessWatchList();
   247 
   248 	CRadioMenuPlayer *pPlayer;
   249 	unsigned int max_clients = g_Players.GetMaxClients();
   250 	for (unsigned int i = 1; i <= max_clients; i++)
   251 	{
   252 		pPlayer = GetRadioMenuPlayer(i);
   253 		if (!pPlayer->bInMenu || pPlayer->bInExternMenu)
   254 		{
   255 			continue;
   256 		}
   257 		if (pPlayer->Radio_NeedsRefresh())
   258 		{
   259 			pPlayer->Radio_Refresh();
   260 		}
   261 	}
   262 }
   263 
   264 CRadioDisplay::CRadioDisplay()
   265 {
   266 	Reset();
   267 }
   268 
   269 CRadioDisplay::CRadioDisplay(CRadioMenu *menu)
   270 {
   271 	Reset();
   272 }
   273 
   274 bool CRadioDisplay::DrawRawLine(const char *rawline)
   275 {
   276 	m_BufferText.append(rawline);
   277 	m_BufferText.append("\n");
   278 	return true;
   279 }
   280 
   281 void CRadioDisplay::Reset()
   282 {
   283 	m_BufferText.assign("");
   284 	m_Title.assign("");
   285 	m_NextPos = 1;
   286 	keys = 0;
   287 }
   288 
   289 void CRadioDisplay::DirectSet(const char *str, int keymap)
   290 {
   291 	m_Title.clear();
   292 	m_BufferText.assign(str);
   293 	keys = keymap;
   294 }
   295 
   296 unsigned int CRadioDisplay::GetCurrentKey()
   297 {
   298 	return m_NextPos;
   299 }
   300 
   301 bool CRadioDisplay::SetCurrentKey(unsigned int key)
   302 {
   303 	if (key < m_NextPos || m_NextPos > 10)
   304 	{
   305 		return false;
   306 	}
   307 
   308 	m_NextPos = key;
   309 
   310 	return true;
   311 }
   312 
   313 bool CRadioDisplay::SendDisplay(int client, IMenuHandler *handler, unsigned int time)
   314 {
   315 	return g_RadioMenuStyle.DoClientMenu(client, this, handler, time);
   316 }
   317 
   318 bool CRadioDisplay::SetExtOption(MenuOption option, const void *valuePtr)
   319 {
   320 	return false;
   321 }
   322 
   323 IMenuStyle *CRadioDisplay::GetParentStyle()
   324 {
   325 	return &g_RadioMenuStyle;
   326 }
   327 
   328 void CRadioDisplay::DrawTitle(const char *text, bool onlyIfEmpty/* =false */)
   329 {
   330 	if (m_Title.size() != 0 && onlyIfEmpty)
   331 	{
   332 		return;
   333 	}
   334 	m_Title.assign(text);
   335 }
   336 
   337 unsigned int CRadioDisplay::DrawItem(const ItemDrawInfo &item)
   338 {
   339 	if (m_NextPos > 10 || !CanDrawItem(item.style))
   340 	{
   341 		return 0;
   342 	}
   343 
   344 	if (item.style & ITEMDRAW_RAWLINE)
   345 	{
   346 		if (item.style & ITEMDRAW_SPACER)
   347 		{
   348 			m_BufferText.append(" \n");
   349 		} else {
   350 			m_BufferText.append(item.display);
   351 			m_BufferText.append("\n");
   352 		}
   353 		return 0;
   354 	} else if (item.style & ITEMDRAW_SPACER) {
   355 		m_BufferText.append(" \n");
   356 		return m_NextPos++;
   357 	} else if (item.style & ITEMDRAW_NOTEXT) {
   358 		return m_NextPos++;
   359 	}
   360 
   361 	if (item.style & ITEMDRAW_DISABLED)
   362 	{
   363 		m_BufferText.append(g_RadioNumTable[m_NextPos]);
   364 		m_BufferText.append(item.display);
   365 		m_BufferText.append("\n");
   366 	} else {
   367 		m_BufferText.append("->");
   368 		m_BufferText.append(g_RadioNumTable[m_NextPos]);
   369 		m_BufferText.append(item.display);
   370 		m_BufferText.append("\n");
   371 		keys |= (1<<(m_NextPos-1));
   372 	}
   373 
   374 	return m_NextPos++;
   375 }
   376 
   377 bool CRadioDisplay::CanDrawItem(unsigned int drawFlags)
   378 {
   379 	if ((drawFlags & ITEMDRAW_IGNORE) == ITEMDRAW_IGNORE)
   380 	{
   381 		return false;
   382 	}
   383 
   384 	if ((drawFlags & ITEMDRAW_DISABLED) && (drawFlags & ITEMDRAW_CONTROL))
   385 	{
   386 		return false;
   387 	}
   388 
   389 	return true;
   390 }
   391 
   392 void CRadioDisplay::SendRawDisplay(int client, unsigned int time)
   393 {
   394 	int _sel_keys = (keys == 0) ? (1<<9) : keys;
   395 	CRadioMenuPlayer *pPlayer = g_RadioMenuStyle.GetRadioMenuPlayer(client);
   396 	pPlayer->Radio_Init(_sel_keys, m_Title.c_str(), m_BufferText.c_str());
   397 	pPlayer->Radio_Refresh();
   398 }
   399 
   400 void CRadioMenuPlayer::Radio_SetIndex(unsigned int index)
   401 {
   402 	m_index = index;
   403 }
   404 
   405 bool CRadioMenuPlayer::Radio_NeedsRefresh()
   406 {
   407 	return (gpGlobals->curtime - display_last_refresh >= g_RadioMenuTimeout);
   408 }
   409 
   410 void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text)
   411 {
   412 	if (title[0] != '\0')
   413 	{
   414 		display_len = UTIL_Format(display_pkt, 
   415 			sizeof(display_pkt), 
   416 			"%s\n%s", 
   417 			title,
   418 			text);
   419 	}
   420 	else
   421 	{
   422 		display_len = UTIL_Format(display_pkt, 
   423 			sizeof(display_pkt), 
   424 			"%s", 
   425 			text);
   426 	}
   427 	display_keys = keys;
   428 }
   429 
   430 void CRadioMenuPlayer::Radio_Refresh()
   431 {
   432 	cell_t players[1] = {m_index};
   433 	char *ptr = display_pkt;
   434 	char save = 0;
   435 	size_t len = display_len;
   436 	unsigned int time;
   437 
   438 	/* Compute the new time */
   439 	if (menuHoldTime == 0)
   440 	{
   441 		time = 0;
   442 	}
   443 	else
   444 	{
   445 		time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
   446 	}
   447 
   448 	while (true)
   449 	{
   450 		if (len > 240)
   451 		{
   452 			save = ptr[240];
   453 			ptr[240] = '\0';
   454 		}
   455 		bf_write *buffer = g_UserMsgs.StartMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
   456 		buffer->WriteWord(display_keys);
   457 		buffer->WriteChar(time ? time : -1);
   458 		buffer->WriteByte( (len > 240) ? 1 : 0 );
   459 		buffer->WriteString(ptr);
   460 		g_UserMsgs.EndMessage();
   461 		if (len > 240)
   462 		{
   463 			ptr[240] = save;
   464 			ptr = &ptr[240];
   465 			len -= 240;
   466 		}
   467 		else
   468 		{
   469 			break;
   470 		}
   471 	}
   472 
   473 	display_last_refresh = gpGlobals->curtime;
   474 }
   475 
   476 int CRadioDisplay::GetAmountRemaining()
   477 {
   478 	size_t amt = m_Title.size() + 1 + m_BufferText.size();
   479 	if (amt >= 511)
   480 	{
   481 		return 0;
   482 	}
   483 	return (int)(511 - amt);
   484 }
   485 
   486 void CRadioDisplay::DeleteThis()
   487 {
   488 	delete this;
   489 }
   490 
   491 bool CRadioDisplay::SetSelectableKeys(unsigned int keymap)
   492 {
   493 	keys = (signed)keymap;
   494 	return true;
   495 }
   496 
   497 CRadioMenu::CRadioMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) : 
   498 CBaseMenu(pHandler, &g_RadioMenuStyle, pOwner)
   499 {
   500 }
   501 
   502 bool CRadioMenu::SetExtOption(MenuOption option, const void *valuePtr)
   503 {
   504 	return false;
   505 }
   506 
   507 IMenuPanel *CRadioMenu::CreatePanel()
   508 {
   509 	return g_RadioMenuStyle.MakeRadioDisplay(this);
   510 }
   511 
   512 bool CRadioMenu::Display(int client, unsigned int time, IMenuHandler *alt_handler)
   513 {
   514 	return DisplayAtItem(client, time, 0, alt_handler);
   515 }
   516 
   517 bool CRadioMenu::DisplayAtItem(int client,
   518 							   unsigned int time,
   519 							   unsigned int start_item,
   520 							   IMenuHandler *alt_handler)
   521 {
   522 #if defined MENU_DEBUG
   523 	g_Logger.LogMessage("[SM_MENU] CRadioMenu::Display(%p) (client %d) (time %d)",
   524 		this,
   525 		client,
   526 		time);
   527 #endif
   528 	if (m_bCancelling)
   529 	{
   530 		return false;
   531 	}
   532 
   533 	return g_RadioMenuStyle.DoClientMenu(client,
   534 		this,
   535 		start_item,
   536 		alt_handler ? alt_handler : m_pHandler, 
   537 		time);
   538 }
   539 
   540 void CRadioMenu::Cancel_Finally()
   541 {
   542 	g_RadioMenuStyle.CancelMenu(this);
   543 }
   544 
   545 const char *g_RadioNumTable[11] = 
   546 {
   547 	"0. ", "1. ", "2. ", "3. ", "4. ", "5. ", "6. ", "7. ", "8. ", "9. ", "0. "
   548 };