Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2028 lines
52 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "hud_basechat.h"
  9. #include <vgui/IScheme.h>
  10. #include <vgui/IVGui.h>
  11. #include "iclientmode.h"
  12. #include "hud_macros.h"
  13. #include "engine/IEngineSound.h"
  14. #include "text_message.h"
  15. #include <vgui/ILocalize.h>
  16. #include "vguicenterprint.h"
  17. #include "vgui/KeyCode.h"
  18. #include <keyvalues.h>
  19. #include "ienginevgui.h"
  20. #include "c_playerresource.h"
  21. #include "cstrike15/c_cs_playerresource.h"
  22. #include "ihudlcd.h"
  23. #include "vgui/IInput.h"
  24. #include "vgui/ILocalize.h"
  25. #include "multiplay_gamerules.h"
  26. #include "time.h"
  27. #include "filesystem.h"
  28. #include "vgui_int.h"
  29. #ifndef NO_STEAM
  30. #include "steam/steam_api.h"
  31. #endif
  32. #if defined( _X360 )
  33. #include "xbox/xbox_win32stubs.h"
  34. #endif
  35. // memdbgon must be the last include file in a .cpp file!!!
  36. #include "tier0/memdbgon.h"
  37. #define CHAT_WIDTH_PERCENTAGE 0.6f
  38. ConVar hud_saytext_time( "hud_saytext_time", "12", 0 );
  39. ConVar cl_showtextmsg( "cl_showtextmsg", "1", 0, "Enable/disable text messages printing on the screen." );
  40. ConVar cl_chat_active( "cl_chat_active", "0" );
  41. ConVar cl_chatfilters( "cl_chatfilters", "63", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Stores the chat filter settings " );
  42. ConVar cl_chatfilter_version( "cl_chatfilter_version", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_HIDDEN, "Stores the chat filter version" );
  43. const int kChatFilterVersion = 1;
  44. Color g_ColorBlue( 153, 204, 255, 255 );
  45. Color g_ColorRed( 255, 63.75, 63.75, 255 );
  46. Color g_ColorGreen( 153, 255, 153, 255 );
  47. Color g_ColorDarkGreen( 64, 255, 64, 255 );
  48. Color g_ColorYellow( 255, 178.5, 0.0, 255 );
  49. Color g_ColorGrey( 204, 204, 204, 255 );
  50. static const char *gBugPriorityTable[] = {
  51. "TODAY",
  52. "ASAP",
  53. "NONE",
  54. NULL
  55. };
  56. static const char *gBugTokenTable[] = {
  57. "re", "regression",
  58. "today", "showstopper",
  59. "asap", "showstopper",
  60. "ss", "showstopper",
  61. "show", "showstopper",
  62. // "high", "high",
  63. "med", "medium",
  64. // "low", "low",
  65. "none", "feature",
  66. "sugg", "feature",
  67. "feat", "feature",
  68. NULL
  69. };
  70. // [jason] Forward Printf messages to the Scaleform voicestatus panel
  71. #if defined ( CSTRIKE15 )
  72. inline void CS15ForwardStatusMsg( const char* text, int clientid )
  73. {
  74. /* Removed for partner depot */
  75. }
  76. inline void CS15ForwardStatusMsg( const wchar_t* text, int clientid )
  77. {
  78. /* Removed for partner depot */
  79. }
  80. #endif // CSTRIKE15
  81. // removes all color markup characters, so Msg can deal with the string properly
  82. // returns a pointer to str
  83. char* RemoveColorMarkup( char *str )
  84. {
  85. char *out = str;
  86. for ( char *in = str; *in != 0; ++in )
  87. {
  88. if ( *in > 0 && *in < COLOR_MAX )
  89. {
  90. continue;
  91. }
  92. *out = *in;
  93. ++out;
  94. }
  95. *out = 0;
  96. return str;
  97. }
  98. // converts all '\r' characters to '\n', so that the engine can deal with the properly
  99. // returns a pointer to str
  100. char* ConvertCRtoNL( char *str )
  101. {
  102. for ( char *ch = str; *ch != 0; ch++ )
  103. if ( *ch == '\r' )
  104. *ch = '\n';
  105. return str;
  106. }
  107. // converts all '\r' characters to '\n', so that the engine can deal with the properly
  108. // returns a pointer to str
  109. wchar_t* ConvertCRtoNL( wchar_t *str )
  110. {
  111. for ( wchar_t *ch = str; *ch != 0; ch++ )
  112. if ( *ch == L'\r' )
  113. *ch = L'\n';
  114. return str;
  115. }
  116. void StripEndNewlineFromString( char *str )
  117. {
  118. int s = strlen( str ) - 1;
  119. if ( s >= 0 )
  120. {
  121. if ( str[s] == '\n' || str[s] == '\r' )
  122. str[s] = 0;
  123. }
  124. }
  125. void StripEndNewlineFromString( wchar_t *str )
  126. {
  127. int s = wcslen( str ) - 1;
  128. if ( s >= 0 )
  129. {
  130. if ( str[s] == L'\n' || str[s] == L'\r' )
  131. str[s] = 0;
  132. }
  133. }
  134. //-----------------------------------------------------------------------------
  135. // Purpose: Reads a string from the current message and checks if it is translatable
  136. //-----------------------------------------------------------------------------
  137. wchar_t* ReadLocalizedString( const char *szString, wchar_t *pOut, int outSize, bool bStripNewline, char *originalString, int originalSize )
  138. {
  139. if ( originalString )
  140. {
  141. Q_strncpy( originalString, szString, originalSize );
  142. }
  143. const wchar_t *pBuf = g_pVGuiLocalize->Find( szString );
  144. if ( pBuf )
  145. {
  146. wcsncpy( pOut, pBuf, outSize/sizeof( wchar_t) );
  147. pOut[outSize/sizeof( wchar_t)-1] = 0;
  148. }
  149. else
  150. {
  151. g_pVGuiLocalize->ConvertANSIToUnicode( szString, pOut, outSize );
  152. }
  153. if ( bStripNewline )
  154. StripEndNewlineFromString( pOut );
  155. return pOut;
  156. }
  157. //-----------------------------------------------------------------------------
  158. // Purpose: Expands shortcuts into longer tokens
  159. //-----------------------------------------------------------------------------
  160. static const char *TranslateToken( const char *pToken)
  161. {
  162. const char **pKey = gBugTokenTable;
  163. while( pKey[0])
  164. {
  165. if ( ! V_stricmp( pKey[0], pToken))
  166. {
  167. return pKey[1];
  168. }
  169. pKey+=2;
  170. }
  171. return pToken;
  172. }
  173. static const char *TranslatePriorityToken( const char *pToken)
  174. {
  175. const char **pKey = gBugPriorityTable;
  176. while( pKey[0])
  177. {
  178. if ( ! V_stricmp( pKey[0], pToken))
  179. {
  180. return pKey[0];
  181. }
  182. pKey++;
  183. }
  184. return NULL;
  185. }
  186. //-----------------------------------------------------------------------------
  187. // Purpose: Converts all the strings in parentheses into a linked list of strings
  188. // It will also null terminate the string at the first parenthesis
  189. //-----------------------------------------------------------------------------
  190. static CUtlLinkedList<const char *> *ParseTokens( char *szString)
  191. {
  192. CUtlLinkedList<const char *> *tokens = new CUtlLinkedList<const char *>();
  193. // ensure that the defaults are reset
  194. // later tokens should override these values
  195. tokens->AddToHead( "NONE");
  196. tokens->AddToHead( "High");
  197. tokens->AddToHead( "triage");
  198. char *pEnd = szString + V_strlen( szString) - 1;
  199. while ( pEnd >= szString && ( *pEnd == ')' || *pEnd == ' ') )
  200. {
  201. if ( *pEnd == ')')
  202. {
  203. char *pToken = NULL;
  204. // skip any spaces
  205. char *pTemp = pEnd - 1;
  206. while( pTemp >= szString && *pTemp == ' ') pTemp--;
  207. if ( pTemp >= szString)
  208. {
  209. pEnd = pTemp+1;
  210. *pEnd = '\0';
  211. }
  212. // skip back to the open paren ( if there is one)
  213. char *pStart = pEnd;
  214. while ( pStart > szString && *pStart != '(') pStart--;
  215. if ( pStart >= szString)
  216. {
  217. *pStart = '\0';
  218. pToken = pStart+1;
  219. }
  220. if ( pToken >= szString && pToken != pEnd)
  221. {
  222. const char *pTranslatedToken = TranslateToken( pToken);
  223. const char *pPriorityToken = TranslatePriorityToken( pToken);
  224. tokens->AddToTail( pTranslatedToken);
  225. if ( pPriorityToken)
  226. {
  227. tokens->AddToTail( pPriorityToken);
  228. }
  229. }
  230. pEnd = pStart;
  231. }
  232. else
  233. {
  234. // Chomp off trailing white space
  235. *pEnd = '\0';
  236. }
  237. pEnd--;
  238. }
  239. return tokens;
  240. }
  241. //-----------------------------------------------------------------------------
  242. // Purpose: Reads a string from the current message, converts it to unicode, and strips out color codes
  243. //-----------------------------------------------------------------------------
  244. wchar_t* ReadChatTextString( const char *szString, wchar_t *pOut, int outSize, bool stripBugData )
  245. {
  246. if ( outSize <= 0 )
  247. return pOut;
  248. // Allow localizing player names
  249. pOut[0] = 0;
  250. if ( const char *pszEntIndex = StringAfterPrefix( szString, "#ENTNAME[" ) )
  251. {
  252. int iEntIndex = V_atoi( pszEntIndex );
  253. if ( C_CS_PlayerResource *pCSPR = ( C_CS_PlayerResource* ) GameResources() )
  254. {
  255. pCSPR->GetDecoratedPlayerName( iEntIndex, pOut, outSize, ( EDecoratedPlayerNameFlag_t ) ( k_EDecoratedPlayerNameFlag_DontUseNameOfControllingPlayer | k_EDecoratedPlayerNameFlag_DontUseAssassinationTargetName ) );
  256. }
  257. if ( !pOut[0] )
  258. {
  259. if ( const char *pszCloseBracket = V_strnchr( pszEntIndex, ']', 64 ) )
  260. szString = pszCloseBracket + 1;
  261. }
  262. }
  263. if ( !pOut[0] )
  264. {
  265. g_pVGuiLocalize->ConvertANSIToUnicode( szString, pOut, outSize );
  266. StripEndNewlineFromString( pOut );
  267. }
  268. // converts color control characters into control characters for the normal color
  269. for ( wchar_t *test = pOut; test && *test; ++test )
  270. {
  271. if ( *test && ( *test < COLOR_MAX ) )
  272. {
  273. *test = COLOR_NORMAL;
  274. }
  275. }
  276. return pOut;
  277. }
  278. //-----------------------------------------------------------------------------
  279. // Purpose:
  280. // Input : *parent -
  281. // *panelName -
  282. //-----------------------------------------------------------------------------
  283. CBaseHudChatLine::CBaseHudChatLine( vgui::Panel *parent, const char *panelName ) :
  284. vgui::RichText( parent, panelName )
  285. {
  286. m_hFont = m_hFontMarlett = 0;
  287. m_flExpireTime = 0.0f;
  288. m_flStartTime = 0.0f;
  289. m_iNameLength = 0;
  290. m_text = NULL;
  291. SetPaintBackgroundEnabled( true );
  292. SetVerticalScrollbar( false );
  293. }
  294. CBaseHudChatLine::~CBaseHudChatLine()
  295. {
  296. if ( m_text )
  297. {
  298. delete[] m_text;
  299. m_text = NULL;
  300. }
  301. }
  302. void CBaseHudChatLine::ApplySchemeSettings( vgui::IScheme *pScheme)
  303. {
  304. BaseClass::ApplySchemeSettings( pScheme);
  305. m_hFont = pScheme->GetFont( "Default" );
  306. SetBgColor( Color( 0, 0, 0, 0 ) );
  307. m_hFontMarlett = pScheme->GetFont( "Marlett" );
  308. m_clrText = pScheme->GetColor( "FgColor", GetFgColor() );
  309. SetFont( m_hFont );
  310. }
  311. void CBaseHudChatLine::PerformFadeout( void )
  312. {
  313. // Flash + Extra bright when new
  314. float curtime = gpGlobals->curtime;
  315. int lr = m_clrText[0];
  316. int lg = m_clrText[1];
  317. int lb = m_clrText[2];
  318. if ( curtime >= m_flStartTime && curtime < m_flStartTime + CHATLINE_FLASH_TIME )
  319. {
  320. float frac1 = ( curtime - m_flStartTime ) / CHATLINE_FLASH_TIME;
  321. float frac = frac1;
  322. frac *= CHATLINE_NUM_FLASHES;
  323. frac *= 2 * M_PI;
  324. frac = cos( frac );
  325. frac = clamp( frac, 0.0f, 1.0f );
  326. frac *= ( 1.0f-frac1);
  327. int r = lr, g = lg, b = lb;
  328. r = r + ( 255 - r ) * frac;
  329. g = g + ( 255 - g ) * frac;
  330. b = b + ( 255 - b ) * frac;
  331. // Draw a right facing triangle in red, faded out over time
  332. int alpha = 63 + 192 * ( 1.0f - frac1 );
  333. alpha = clamp( alpha, 0, 255 );
  334. wchar_t wbuf[4096];
  335. GetText( 0, wbuf, sizeof( wbuf));
  336. SetText( "" );
  337. InsertColorChange( Color( r, g, b, 255 ) );
  338. InsertString( wbuf );
  339. }
  340. else if ( curtime <= m_flExpireTime && curtime > m_flExpireTime - CHATLINE_FADE_TIME )
  341. {
  342. float frac = ( m_flExpireTime - curtime ) / CHATLINE_FADE_TIME;
  343. int alpha = frac * 255;
  344. alpha = clamp( alpha, 0, 255 );
  345. wchar_t wbuf[4096];
  346. GetText( 0, wbuf, sizeof( wbuf));
  347. SetText( "" );
  348. InsertColorChange( Color( lr * frac, lg * frac, lb * frac, alpha ) );
  349. InsertString( wbuf );
  350. }
  351. else
  352. {
  353. wchar_t wbuf[4096];
  354. GetText( 0, wbuf, sizeof( wbuf));
  355. SetText( "" );
  356. InsertColorChange( Color( lr, lg, lb, 255 ) );
  357. InsertString( wbuf );
  358. }
  359. OnThink();
  360. }
  361. //-----------------------------------------------------------------------------
  362. // Purpose:
  363. // Input : time -
  364. //-----------------------------------------------------------------------------
  365. void CBaseHudChatLine::SetExpireTime( void )
  366. {
  367. m_flStartTime = gpGlobals->curtime;
  368. m_flExpireTime = m_flStartTime + hud_saytext_time.GetFloat();
  369. m_nCount = CBaseHudChat::m_nLineCounter++;
  370. }
  371. //-----------------------------------------------------------------------------
  372. // Purpose:
  373. //-----------------------------------------------------------------------------
  374. int CBaseHudChatLine::GetCount( void )
  375. {
  376. return m_nCount;
  377. }
  378. //-----------------------------------------------------------------------------
  379. // Purpose:
  380. // Output : Returns true on success, false on failure.
  381. //-----------------------------------------------------------------------------
  382. bool CBaseHudChatLine::IsReadyToExpire( void )
  383. {
  384. // Engine disconnected, expire right away
  385. if ( !engine->IsInGame() && !engine->IsConnected() )
  386. return true;
  387. if ( gpGlobals->curtime >= m_flExpireTime )
  388. return true;
  389. return false;
  390. }
  391. //-----------------------------------------------------------------------------
  392. // Purpose:
  393. // Output : float
  394. //-----------------------------------------------------------------------------
  395. float CBaseHudChatLine::GetStartTime( void )
  396. {
  397. return m_flStartTime;
  398. }
  399. //-----------------------------------------------------------------------------
  400. // Purpose:
  401. //-----------------------------------------------------------------------------
  402. void CBaseHudChatLine::Expire( void )
  403. {
  404. SetVisible( false );
  405. // Spit out label text now
  406. // char text[ 256 ];
  407. // GetText( text, 256 );
  408. // Msg( "%s\n", text );
  409. }
  410. //-----------------------------------------------------------------------------
  411. // Purpose: The prompt and text entry area for chat messages
  412. //-----------------------------------------------------------------------------
  413. CBaseHudChatInputLine::CBaseHudChatInputLine( CBaseHudChat *parent, char const *panelName ) :
  414. vgui::Panel( parent, panelName )
  415. {
  416. SetMouseInputEnabled( false );
  417. m_pPrompt = new vgui::Label( this, "ChatInputPrompt", L"Enter text:" );
  418. m_pInput = new CBaseHudChatEntry( this, "ChatInput", parent );
  419. m_pInput->SetMaximumCharCount( 127 );
  420. }
  421. void CBaseHudChatInputLine::ApplySchemeSettings( vgui::IScheme *pScheme)
  422. {
  423. BaseClass::ApplySchemeSettings( pScheme);
  424. // FIXME: Outline
  425. vgui::HFont hFont = pScheme->GetFont( "ChatFont" );
  426. m_pPrompt->SetFont( hFont );
  427. m_pInput->SetFont( hFont );
  428. m_pInput->SetFgColor( pScheme->GetColor( "Chat.TypingText", pScheme->GetColor( "Panel.FgColor", Color( 255, 255, 255, 255 ) ) ) );
  429. SetPaintBackgroundEnabled( true );
  430. m_pPrompt->SetPaintBackgroundEnabled( true );
  431. m_pPrompt->SetContentAlignment( vgui::Label::a_west );
  432. m_pPrompt->SetTextInset( 2, 0 );
  433. m_pInput->SetMouseInputEnabled( true );
  434. SetBgColor( Color( 0, 0, 0, 0) );
  435. }
  436. void CBaseHudChatInputLine::SetPrompt( const wchar_t *prompt )
  437. {
  438. Assert( m_pPrompt );
  439. m_pPrompt->SetText( prompt );
  440. InvalidateLayout();
  441. }
  442. void CBaseHudChatInputLine::ClearEntry( void )
  443. {
  444. Assert( m_pInput );
  445. SetEntry( L"" );
  446. }
  447. void CBaseHudChatInputLine::SetEntry( const wchar_t *entry )
  448. {
  449. Assert( m_pInput );
  450. Assert( entry );
  451. m_pInput->SetText( entry );
  452. if ( entry && wcslen( entry ) > 0 )
  453. {
  454. m_pInput->GotoEndOfLine();
  455. }
  456. }
  457. void CBaseHudChatInputLine::GetMessageText( wchar_t *buffer, int buffersizebytes )
  458. {
  459. m_pInput->GetText( buffer, buffersizebytes);
  460. }
  461. void CBaseHudChatInputLine::PerformLayout()
  462. {
  463. BaseClass::PerformLayout();
  464. int wide, tall;
  465. GetSize( wide, tall );
  466. int w,h;
  467. m_pPrompt->GetContentSize( w, h);
  468. m_pPrompt->SetBounds( 0, 0, w, tall );
  469. m_pInput->SetBounds( w + 2, 0, wide - w - 2 , tall );
  470. }
  471. vgui::Panel *CBaseHudChatInputLine::GetInputPanel( void )
  472. {
  473. return m_pInput;
  474. }
  475. CHudChatFilterButton::CHudChatFilterButton( vgui::Panel *pParent, const char *pName, const char *pText ) :
  476. BaseClass( pParent, pName, pText )
  477. {
  478. }
  479. CHudChatFilterCheckButton::CHudChatFilterCheckButton( vgui::Panel *pParent, const char *pName, const char *pText, int iFlag ) :
  480. BaseClass( pParent, pName, pText )
  481. {
  482. m_iFlag = iFlag;
  483. }
  484. CHudChatFilterPanel::CHudChatFilterPanel( vgui::Panel *pParent, const char *pName ) : BaseClass ( pParent, pName )
  485. {
  486. pParent->SetSize( 10, 10 ); // Quiet "parent not sized yet" spew
  487. SetParent( pParent );
  488. new CHudChatFilterCheckButton( this, "joinleave_button", "Sky is blue?", CHAT_FILTER_JOINLEAVE );
  489. new CHudChatFilterCheckButton( this, "namechange_button", "Sky is blue?", CHAT_FILTER_NAMECHANGE );
  490. new CHudChatFilterCheckButton( this, "publicchat_button", "Sky is blue?", CHAT_FILTER_PUBLICCHAT );
  491. new CHudChatFilterCheckButton( this, "servermsg_button", "Sky is blue?", CHAT_FILTER_SERVERMSG );
  492. new CHudChatFilterCheckButton( this, "teamchange_button", "Sky is blue?", CHAT_FILTER_TEAMCHANGE );
  493. new CHudChatFilterCheckButton( this, "achivement_button", "Sky is blue?", CHAT_FILTER_ACHIEVEMENT );
  494. }
  495. void CHudChatFilterPanel::ApplySchemeSettings( vgui::IScheme *pScheme)
  496. {
  497. if ( IsGameConsole() )
  498. {
  499. // not used
  500. BaseClass::SetVisible( false );
  501. return;
  502. }
  503. LoadControlSettings( "resource/UI/ChatFilters.res" );
  504. BaseClass::ApplySchemeSettings( pScheme );
  505. Color cColor = pScheme->GetColor( "DullWhite", GetBgColor() );
  506. SetBgColor( Color ( cColor.r(), cColor.g(), cColor.b(), 0 ) );
  507. SetFgColor( pScheme->GetColor( "Blank", GetFgColor() ) );
  508. }
  509. void CHudChatFilterPanel::OnFilterButtonChecked( vgui::Panel *panel )
  510. {
  511. if ( IsGameConsole() )
  512. {
  513. // not used
  514. return;
  515. }
  516. CHudChatFilterCheckButton *pButton = dynamic_cast < CHudChatFilterCheckButton * > ( panel );
  517. if ( pButton && GetChatParent() && IsVisible() )
  518. {
  519. if ( pButton->IsSelected() )
  520. {
  521. GetChatParent()->SetFilterFlag( GetChatParent()->GetFilterFlags() | pButton->GetFilterFlag() );
  522. }
  523. else
  524. {
  525. GetChatParent()->SetFilterFlag( GetChatParent()->GetFilterFlags() & ~ pButton->GetFilterFlag() );
  526. }
  527. }
  528. }
  529. void CHudChatFilterPanel::SetVisible( bool state)
  530. {
  531. if ( IsGameConsole() )
  532. {
  533. // not used
  534. return;
  535. }
  536. if ( state == true )
  537. {
  538. for ( int i = 0; i < GetChildCount(); i++)
  539. {
  540. CHudChatFilterCheckButton *pButton = dynamic_cast < CHudChatFilterCheckButton * > ( GetChild( i) );
  541. if ( pButton )
  542. {
  543. if ( cl_chatfilters.GetInt() & pButton->GetFilterFlag() )
  544. {
  545. pButton->SetSelected( true );
  546. }
  547. else
  548. {
  549. pButton->SetSelected( false );
  550. }
  551. }
  552. }
  553. }
  554. BaseClass::SetVisible( state );
  555. }
  556. void CHudChatFilterButton::DoClick( void )
  557. {
  558. if ( IsGameConsole() )
  559. {
  560. // not used
  561. return;
  562. }
  563. BaseClass::DoClick();
  564. CBaseHudChat *pChat = dynamic_cast < CBaseHudChat * > ( GetParent() );
  565. if ( pChat )
  566. {
  567. pChat->GetChatInput()->RequestFocus();
  568. if ( pChat->GetChatFilterPanel() )
  569. {
  570. if ( pChat->GetChatFilterPanel()->IsVisible() )
  571. {
  572. pChat->GetChatFilterPanel()->SetVisible( false );
  573. }
  574. else
  575. {
  576. pChat->GetChatFilterPanel()->SetVisible( true );
  577. pChat->GetChatFilterPanel()->MakePopup();
  578. pChat->GetChatFilterPanel()->SetMouseInputEnabled( true );
  579. }
  580. }
  581. }
  582. }
  583. CHudChatHistory::CHudChatHistory( vgui::Panel *pParent, const char *panelName ) : BaseClass( pParent, "HudChatHistory" )
  584. {
  585. SetScheme( "ChatScheme" );
  586. InsertFade( -1, -1 );
  587. }
  588. void CHudChatHistory::ApplySchemeSettings( vgui::IScheme *pScheme )
  589. {
  590. BaseClass::ApplySchemeSettings( pScheme );
  591. SetFont( pScheme->GetFont( "ChatFont" ) );
  592. }
  593. void CHudChatHistory::ApplySettings( KeyValues *inResourceData )
  594. {
  595. BaseClass::ApplySettings( inResourceData );
  596. #if defined ( PORTAL2 )
  597. // We don't fade out and clear text for portal2, so set a maximum size for the buffer
  598. SetMaximumCharCount( 1024 );
  599. #endif
  600. }
  601. void CHudChatHistory::Paint()
  602. {
  603. BaseClass::Paint();
  604. // 84928: Messages/Instructions from coop partners are important and
  605. // we don't want to have them disappear. Keep them on and let them spam.
  606. #if !defined ( PORTAL2 )
  607. if ( IsAllTextAlphaZero() && HasText() )
  608. {
  609. SetText( "" );
  610. // Wipe
  611. }
  612. #endif
  613. }
  614. CBaseHudChat *g_pHudChat = NULL;
  615. CBaseHudChat *CBaseHudChat::GetHudChat( void )
  616. {
  617. Assert( g_pHudChat );
  618. return g_pHudChat;
  619. }
  620. int CBaseHudChat::m_nLineCounter = 1;
  621. //-----------------------------------------------------------------------------
  622. // Purpose: Text chat input/output hud element
  623. //-----------------------------------------------------------------------------
  624. CBaseHudChat::CBaseHudChat( const char *pElementName )
  625. : CHudElement( pElementName ), BaseClass( NULL, "HudChat" )
  626. {
  627. Assert( g_pHudChat == NULL );
  628. g_pHudChat = this;
  629. vgui::Panel *pParent = GetFullscreenClientMode()->GetViewport();
  630. SetParent( pParent );
  631. vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( NULL, "resource/ChatScheme.res", "ChatScheme" );
  632. SetScheme( scheme);
  633. #if !defined( CSTRIKE15 )
  634. g_pVGuiLocalize->AddFile( "resource/chat_%language%.txt" );
  635. #endif
  636. m_nMessageMode = MM_NONE;
  637. cl_chat_active.SetValue( m_nMessageMode );
  638. vgui::ivgui()->AddTickSignal( GetVPanel() );
  639. // ( We don't actually want input until they bring up the chat line).
  640. MakePopup();
  641. SetZPos( -30 );
  642. SetHiddenBits( HIDEHUD_CHAT );
  643. m_pFiltersButton = new CHudChatFilterButton( this, "ChatFiltersButton", "#chat_filterbutton" );
  644. if ( m_pFiltersButton )
  645. {
  646. m_pFiltersButton->SetScheme( scheme );
  647. m_pFiltersButton->SetVisible( true );
  648. m_pFiltersButton->SetEnabled( true );
  649. m_pFiltersButton->SetMouseInputEnabled( true );
  650. m_pFiltersButton->SetKeyBoardInputEnabled( false );
  651. }
  652. m_pChatHistory = new CHudChatHistory( this, "HudChatHistory" );
  653. CreateChatLines();
  654. CreateChatInputLine();
  655. GetChatFilterPanel();
  656. m_iFilterFlags = cl_chatfilters.GetInt();
  657. }
  658. CBaseHudChat::~CBaseHudChat()
  659. {
  660. g_pHudChat = NULL;
  661. }
  662. void CBaseHudChat::CreateChatInputLine( void )
  663. {
  664. m_pChatInput = new CBaseHudChatInputLine( this, "ChatInputLine" );
  665. m_pChatInput->SetVisible( false );
  666. if ( GetChatHistory() )
  667. {
  668. GetChatHistory()->SetMaximumCharCount( 127 * 100 );
  669. GetChatHistory()->SetVisible( true );
  670. }
  671. }
  672. void CBaseHudChat::CreateChatLines( void )
  673. {
  674. m_ChatLine = new CBaseHudChatLine( this, "ChatLine1" );
  675. m_ChatLine->SetVisible( false );
  676. }
  677. #define BACKGROUND_BORDER_WIDTH 20
  678. CHudChatFilterPanel *CBaseHudChat::GetChatFilterPanel( void )
  679. {
  680. if ( m_pFilterPanel == NULL )
  681. {
  682. m_pFilterPanel = new CHudChatFilterPanel( this, "HudChatFilterPanel" );
  683. if ( m_pFilterPanel )
  684. {
  685. m_pFilterPanel->SetScheme( "ChatScheme" );
  686. m_pFilterPanel->InvalidateLayout( true, true );
  687. m_pFilterPanel->SetMouseInputEnabled( true );
  688. m_pFilterPanel->SetPaintBackgroundType( 2 );
  689. m_pFilterPanel->SetPaintBorderEnabled( true );
  690. m_pFilterPanel->SetVisible( false );
  691. }
  692. }
  693. return m_pFilterPanel;
  694. }
  695. void CBaseHudChat::ApplySchemeSettings( vgui::IScheme *pScheme )
  696. {
  697. LoadControlSettings( "resource/UI/BaseChat.res" );
  698. BaseClass::ApplySchemeSettings( pScheme );
  699. SetPaintBackgroundType( 2 );
  700. SetPaintBorderEnabled( true );
  701. SetPaintBackgroundEnabled( true );
  702. SetKeyBoardInputEnabled( false );
  703. SetMouseInputEnabled( false );
  704. Color cColor = pScheme->GetColor( "DullWhite", GetBgColor() );
  705. SetBgColor( Color ( cColor.r(), cColor.g(), cColor.b(), 0 ) );
  706. GetChatHistory()->SetVerticalScrollbar( false );
  707. if ( IsGameConsole() )
  708. {
  709. // console has no keyboard
  710. // panel not used as input, only as output of chat history
  711. SetPaintBackgroundEnabled( false );
  712. m_pChatInput->SetVisible( false );
  713. m_ChatLine->SetVisible( false );
  714. m_pFiltersButton->SetVisible( false );
  715. m_pFilterPanel->SetVisible( false );
  716. GetChatHistory()->SetBgColor( Color( 0, 0, 0, 0 ) );
  717. }
  718. FadeChatHistory();
  719. }
  720. void CBaseHudChat::Reset( void )
  721. {
  722. Clear();
  723. }
  724. void CBaseHudChat::Paint( void )
  725. {
  726. }
  727. CHudChatHistory *CBaseHudChat::GetChatHistory( void )
  728. {
  729. return m_pChatHistory;
  730. }
  731. void CBaseHudChat::Init( void )
  732. {
  733. ListenForGameEvent( "hltv_chat" );
  734. }
  735. //-----------------------------------------------------------------------------
  736. // Purpose:
  737. // Input : *pszName -
  738. // iSize -
  739. // *pbuf -
  740. //-----------------------------------------------------------------------------
  741. bool CBaseHudChat::MsgFunc_SayText( const CCSUsrMsg_SayText &msg )
  742. {
  743. int client = msg.ent_idx();
  744. const char *szString = msg.text().c_str();
  745. bool bWantsToChat = msg.chat() ? true : false;
  746. if ( bWantsToChat )
  747. {
  748. // print raw chat text
  749. ChatPrintf( client, CHAT_FILTER_NONE, "%s", szString );
  750. }
  751. else
  752. {
  753. // try to lookup translated string
  754. Printf( CHAT_FILTER_NONE, "%s", hudtextmessage->LookupString( szString ) );
  755. }
  756. CLocalPlayerFilter filter;
  757. C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "HudChat.Message" );
  758. // TERROR: color console echo
  759. //Msg( "%s", szString );
  760. return true;
  761. }
  762. int CBaseHudChat::GetFilterForString( const char *pString )
  763. {
  764. if ( !Q_stricmp( pString, "#HL_Name_Change" ) )
  765. {
  766. return CHAT_FILTER_NAMECHANGE;
  767. }
  768. return CHAT_FILTER_NONE;
  769. }
  770. //-----------------------------------------------------------------------------
  771. // Purpose: Reads in a player's Chat text from the server
  772. //-----------------------------------------------------------------------------
  773. bool CBaseHudChat::MsgFunc_SayText2( const CCSUsrMsg_SayText2 &msg )
  774. {
  775. // Got message during connection
  776. if ( !g_PR )
  777. return true;;
  778. int client = msg.ent_idx();
  779. bool bWantsToChat = msg.chat() ? true : false;
  780. wchar_t szBuf[6][256];
  781. char untranslated_msg_text[256];
  782. wchar_t *msg_text = ReadLocalizedString( msg.msg_name().c_str(), szBuf[0], sizeof( szBuf[0] ), false, untranslated_msg_text, sizeof( untranslated_msg_text ) );
  783. // keep reading strings and using C format strings for subsituting the strings into the localised text string
  784. ReadChatTextString ( msg.params(0).c_str(), szBuf[1], sizeof( szBuf[1] ) ); // player name
  785. ReadChatTextString ( msg.params(1).c_str(), szBuf[2], sizeof( szBuf[2] ), true ); // chat text
  786. ReadLocalizedString( msg.params(2).c_str(), szBuf[3], sizeof( szBuf[3] ), true );
  787. ReadLocalizedString( msg.params(3).c_str(), szBuf[4], sizeof( szBuf[4] ), true );
  788. g_pVGuiLocalize->ConstructString( szBuf[5], sizeof( szBuf[5] ), msg_text, 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] );
  789. char ansiString[512];
  790. g_pVGuiLocalize->ConvertUnicodeToANSI( ConvertCRtoNL( szBuf[5] ), ansiString, sizeof( ansiString ) );
  791. if ( bWantsToChat )
  792. {
  793. int iFilter = CHAT_FILTER_NONE;
  794. if ( client > 0 && ( g_PR->GetTeam( client ) != g_PR->GetTeam( GetLocalPlayerIndex() )) )
  795. {
  796. iFilter = CHAT_FILTER_PUBLICCHAT;
  797. }
  798. // print raw chat text
  799. ChatPrintf( client, iFilter, "%s", ansiString );
  800. // Msg( "%s\n", RemoveColorMarkup( ansiString) );
  801. CLocalPlayerFilter filter;
  802. C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "HudChat.Message" );
  803. }
  804. else
  805. {
  806. // print raw chat text
  807. ChatPrintf( client, GetFilterForString( untranslated_msg_text), "%s", ansiString );
  808. }
  809. return true;
  810. }
  811. //-----------------------------------------------------------------------------
  812. // Message handler for text messages
  813. // displays a string, looking them up from the titles.txt file, which can be localised
  814. // parameters:
  815. // byte: message direction ( HUD_PRINTCONSOLE, HUD_PRINTNOTIFY, HUD_PRINTCENTER, HUD_PRINTTALK )
  816. // string: message
  817. // optional parameters:
  818. // string: message parameter 1
  819. // string: message parameter 2
  820. // string: message parameter 3
  821. // string: message parameter 4
  822. // any string that starts with the character '#' is a message name, and is used to look up the real message in titles.txt
  823. // the next ( optional) one to four strings are parameters for that string ( which can also be message names if they begin with '#')
  824. //-----------------------------------------------------------------------------
  825. bool CBaseHudChat::MsgFunc_TextMsg( const CCSUsrMsg_TextMsg &msg )
  826. {
  827. char szString[2048] = {};
  828. int msg_dest = msg.msg_dst();
  829. wchar_t szBuf[5][256] = {};
  830. wchar_t outputBuf[256] = {};
  831. for ( int i=0; i<5; ++i )
  832. {
  833. // Allow localizing player names
  834. if ( const char *pszEntIndex = StringAfterPrefix( msg.params(i).c_str(), "#ENTNAME[" ) )
  835. {
  836. int iEntIndex = V_atoi( pszEntIndex );
  837. wchar_t wszPlayerName[MAX_DECORATED_PLAYER_NAME_LENGTH] = {};
  838. if ( C_CS_PlayerResource *pCSPR = ( C_CS_PlayerResource* ) GameResources() )
  839. {
  840. pCSPR->GetDecoratedPlayerName( iEntIndex, wszPlayerName, sizeof( wszPlayerName ), ( EDecoratedPlayerNameFlag_t ) ( k_EDecoratedPlayerNameFlag_DontUseNameOfControllingPlayer | k_EDecoratedPlayerNameFlag_DontUseAssassinationTargetName ) );
  841. }
  842. if ( wszPlayerName[0] )
  843. {
  844. szString[0] = 0;
  845. V_wcscpy_safe( szBuf[ i ], wszPlayerName );
  846. }
  847. else if ( const char *pszEndBracket = V_strnchr( pszEntIndex, ']', 64 ) )
  848. {
  849. V_strcpy_safe( szString, pszEndBracket + 1 );
  850. }
  851. else
  852. {
  853. V_strcpy_safe( szString, msg.params(i).c_str() );
  854. }
  855. }
  856. else
  857. {
  858. V_strcpy_safe( szString, msg.params(i).c_str() );
  859. }
  860. if ( szString[0] )
  861. {
  862. char *tmpStr = hudtextmessage->LookupString( szString, &msg_dest );
  863. bool bTranslated = false;
  864. if ( tmpStr[ 0 ] == '#' ) // only translate parameters intended as localization tokens
  865. {
  866. const wchar_t *pBuf = g_pVGuiLocalize->Find( tmpStr );
  867. if ( pBuf )
  868. {
  869. // Copy pBuf into szBuf[i].
  870. int nMaxChars = sizeof( szBuf[ i ] ) / sizeof( wchar_t );
  871. wcsncpy( szBuf[ i ], pBuf, nMaxChars );
  872. szBuf[ i ][ nMaxChars - 1 ] = 0;
  873. bTranslated = true;
  874. }
  875. }
  876. if ( !bTranslated )
  877. {
  878. if ( i )
  879. {
  880. StripEndNewlineFromString( tmpStr ); // these strings are meant for substitution into the main strings, so cull the automatic end newlines
  881. }
  882. g_pVGuiLocalize->ConvertANSIToUnicode( tmpStr, szBuf[ i ], sizeof( szBuf[ i ] ) );
  883. }
  884. }
  885. }
  886. if ( !cl_showtextmsg.GetInt() )
  887. return true;
  888. int len;
  889. switch ( msg_dest )
  890. {
  891. case HUD_PRINTCENTER:
  892. g_pVGuiLocalize->ConstructString( outputBuf, sizeof( outputBuf), szBuf[0], 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] );
  893. GetCenterPrint()->Print( ConvertCRtoNL( outputBuf ) );
  894. break;
  895. case HUD_PRINTNOTIFY:
  896. g_pVGuiLocalize->ConstructString( outputBuf, sizeof( outputBuf), szBuf[0], 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] );
  897. g_pVGuiLocalize->ConvertUnicodeToANSI( outputBuf, szString, sizeof( szString) );
  898. len = strlen( szString );
  899. if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' )
  900. {
  901. Q_strncat( szString, "\n", sizeof( szString), 1 );
  902. }
  903. Msg( "%s", ConvertCRtoNL( szString ) );
  904. break;
  905. case HUD_PRINTTALK:
  906. g_pVGuiLocalize->ConstructString( outputBuf, sizeof( outputBuf), szBuf[0], 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] );
  907. g_pVGuiLocalize->ConvertUnicodeToANSI( outputBuf, szString, sizeof( szString) );
  908. len = strlen( szString );
  909. if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' )
  910. {
  911. Q_strncat( szString, "\n", sizeof( szString), 1 );
  912. }
  913. Printf( CHAT_FILTER_NONE, "%s", ConvertCRtoNL( szString ) );
  914. // TERROR: color console echo
  915. //Msg( "%s", ConvertCRtoNL( szString ) );
  916. break;
  917. case HUD_PRINTCONSOLE:
  918. g_pVGuiLocalize->ConstructString( outputBuf, sizeof( outputBuf), szBuf[0], 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] );
  919. g_pVGuiLocalize->ConvertUnicodeToANSI( outputBuf, szString, sizeof( szString) );
  920. len = strlen( szString );
  921. if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' )
  922. {
  923. Q_strncat( szString, "\n", sizeof( szString), 1 );
  924. }
  925. Msg( "%s", ConvertCRtoNL( szString ) );
  926. break;
  927. }
  928. return true;
  929. }
  930. void CBaseHudChat::MsgFunc_VoiceSubtitle( bf_read &msg )
  931. {
  932. // Got message during connection
  933. if ( !g_PR )
  934. return;
  935. if ( !cl_showtextmsg.GetInt() )
  936. return;
  937. char szString[2048];
  938. char szPrefix[64]; //( Voice)
  939. wchar_t szBuf[128];
  940. int client = msg.ReadByte();
  941. int iMenu = msg.ReadByte();
  942. int iItem = msg.ReadByte();
  943. const char *pszSubtitle = "";
  944. CGameRules *pGameRules = GameRules();
  945. CMultiplayRules *pMultiRules = dynamic_cast< CMultiplayRules * >( pGameRules );
  946. Assert( pMultiRules );
  947. if ( pMultiRules )
  948. {
  949. pszSubtitle = pMultiRules->GetVoiceCommandSubtitle( iMenu, iItem );
  950. }
  951. SetVoiceSubtitleState( true );
  952. const wchar_t *pBuf = g_pVGuiLocalize->Find( pszSubtitle );
  953. if ( pBuf )
  954. {
  955. // Copy pBuf into szBuf[i].
  956. int nMaxChars = sizeof( szBuf ) / sizeof( wchar_t );
  957. wcsncpy( szBuf, pBuf, nMaxChars );
  958. szBuf[nMaxChars-1] = 0;
  959. }
  960. else
  961. {
  962. g_pVGuiLocalize->ConvertANSIToUnicode( pszSubtitle, szBuf, sizeof( szBuf) );
  963. }
  964. int len;
  965. g_pVGuiLocalize->ConvertUnicodeToANSI( szBuf, szString, sizeof( szString) );
  966. len = strlen( szString );
  967. if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' )
  968. {
  969. Q_strncat( szString, "\n", sizeof( szString), 1 );
  970. }
  971. const wchar_t *pVoicePrefix = g_pVGuiLocalize->Find( "#Voice" );
  972. g_pVGuiLocalize->ConvertUnicodeToANSI( pVoicePrefix, szPrefix, sizeof( szPrefix) );
  973. ChatPrintf( client, CHAT_FILTER_NONE, "%c(%s) %s%c: %s", COLOR_PLAYERNAME, szPrefix, GetDisplayedSubtitlePlayerName( client ), COLOR_NORMAL, ConvertCRtoNL( szString ) );
  974. SetVoiceSubtitleState( false );
  975. }
  976. const char *CBaseHudChat::GetDisplayedSubtitlePlayerName( int clientIndex )
  977. {
  978. return g_PR->GetPlayerName( clientIndex );
  979. }
  980. static int __cdecl SortLines( void const *line1, void const *line2 )
  981. {
  982. CBaseHudChatLine *l1 = *( CBaseHudChatLine ** )line1;
  983. CBaseHudChatLine *l2 = *( CBaseHudChatLine ** )line2;
  984. // Invisible at bottom
  985. if ( l1->IsVisible() && !l2->IsVisible() )
  986. return -1;
  987. else if ( !l1->IsVisible() && l2->IsVisible() )
  988. return 1;
  989. // Oldest start time at top
  990. if ( l1->GetStartTime() < l2->GetStartTime() )
  991. return -1;
  992. else if ( l1->GetStartTime() > l2->GetStartTime() )
  993. return 1;
  994. // Otherwise, compare counter
  995. if ( l1->GetCount() < l2->GetCount() )
  996. return -1;
  997. else if ( l1->GetCount() > l2->GetCount() )
  998. return 1;
  999. return 0;
  1000. }
  1001. //-----------------------------------------------------------------------------
  1002. // Purpose: Allow inheriting classes to change this spacing behavior
  1003. //-----------------------------------------------------------------------------
  1004. int CBaseHudChat::GetChatInputOffset( void )
  1005. {
  1006. return m_iFontHeight;
  1007. }
  1008. //-----------------------------------------------------------------------------
  1009. // Purpose: Do repositioning here to avoid latency due to repositioning of vgui
  1010. // voice manager icon panel
  1011. //-----------------------------------------------------------------------------
  1012. void CBaseHudChat::OnTick( void )
  1013. {
  1014. CBaseHudChatLine *line = m_ChatLine;
  1015. if ( line )
  1016. {
  1017. vgui::HFont font = line->GetFont();
  1018. m_iFontHeight = vgui::surface()->GetFontTall( font ) + 2;
  1019. int iChatX, iChatY, iChatW, iChatH;
  1020. GetBounds( iChatX, iChatY, iChatW, iChatH );
  1021. // Put input area at bottom
  1022. int iInputX, iInputY, iInputW, iInputH;
  1023. m_pChatInput->GetBounds( iInputX, iInputY, iInputW, iInputH );
  1024. m_pChatInput->SetBounds( iInputX, iChatH - ( m_iFontHeight * 1.75), iInputW, m_iFontHeight );
  1025. //Resize the History Panel so it fits more lines depending on the screen resolution.
  1026. int iChatHistoryX, iChatHistoryY, iChatHistoryW, iChatHistoryH;
  1027. GetChatHistory()->GetBounds( iChatHistoryX, iChatHistoryY, iChatHistoryW, iChatHistoryH );
  1028. iChatHistoryH = ( iChatH - ( m_iFontHeight * 2.25)) - iChatHistoryY;
  1029. GetChatHistory()->SetBounds( iChatHistoryX, iChatHistoryY, iChatHistoryW, iChatHistoryH );
  1030. }
  1031. FadeChatHistory();
  1032. if ( IsGameConsole() )
  1033. {
  1034. // force to one time only for layout
  1035. vgui::ivgui()->RemoveTickSignal( GetVPanel() );
  1036. }
  1037. }
  1038. //-----------------------------------------------------------------------------
  1039. // Purpose:
  1040. // Input : width -
  1041. // *text -
  1042. // textlen -
  1043. // Output : int
  1044. //-----------------------------------------------------------------------------
  1045. int CBaseHudChat::ComputeBreakChar( int width, const char *text, int textlen )
  1046. {
  1047. CBaseHudChatLine *line = m_ChatLine;
  1048. vgui::HFont font = line->GetFont();
  1049. int currentlen = 0;
  1050. int lastbreak = textlen;
  1051. for ( int i = 0; i < textlen ; i++)
  1052. {
  1053. char ch = text[i];
  1054. if ( ch <= 32 )
  1055. {
  1056. lastbreak = i;
  1057. }
  1058. wchar_t wch[2];
  1059. g_pVGuiLocalize->ConvertANSIToUnicode( &ch, wch, sizeof( wch ) );
  1060. int a,b,c;
  1061. vgui::surface()->GetCharABCwide( font, wch[0], a, b, c);
  1062. currentlen += a + b + c;
  1063. if ( currentlen >= width )
  1064. {
  1065. // If we haven't found a whitespace char to break on before getting
  1066. // to the end, but it's still too long, break on the character just before
  1067. // this one
  1068. if ( lastbreak == textlen )
  1069. {
  1070. lastbreak = MAX( 0, i - 1 );
  1071. }
  1072. break;
  1073. }
  1074. }
  1075. if ( currentlen >= width )
  1076. {
  1077. return lastbreak;
  1078. }
  1079. return textlen;
  1080. }
  1081. //-----------------------------------------------------------------------------
  1082. // Purpose:
  1083. // Input : *fmt -
  1084. // ... -
  1085. //-----------------------------------------------------------------------------
  1086. void CBaseHudChat::Printf( int iFilter, const char *fmt, ... )
  1087. {
  1088. va_list marker;
  1089. char msg[4096];
  1090. va_start( marker, fmt);
  1091. Q_vsnprintf( msg, sizeof( msg), fmt, marker);
  1092. va_end( marker);
  1093. ChatPrintf( 0, iFilter, "%s", msg );
  1094. }
  1095. //-----------------------------------------------------------------------------
  1096. // Purpose:
  1097. //-----------------------------------------------------------------------------
  1098. void CBaseHudChat::StartMessageMode( int iMessageModeType )
  1099. {
  1100. m_nMessageMode = iMessageModeType;
  1101. cl_chat_active.SetValue( m_nMessageMode );
  1102. if ( !IsGameConsole() )
  1103. {
  1104. m_pChatInput->ClearEntry();
  1105. SetChatPrompt( iMessageModeType );
  1106. if ( GetChatHistory() )
  1107. {
  1108. // TERROR: hack to get ChatFont back
  1109. GetChatHistory()->SetFont( vgui::scheme()->GetIScheme( GetScheme() )->GetFont( "ChatFont", false ) );
  1110. GetChatHistory()->SetMouseInputEnabled( true );
  1111. GetChatHistory()->SetKeyBoardInputEnabled( false );
  1112. GetChatHistory()->SetVerticalScrollbar( true );
  1113. GetChatHistory()->ResetAllFades( true );
  1114. GetChatHistory()->SetPaintBorderEnabled( true );
  1115. GetChatHistory()->SetVisible( true );
  1116. }
  1117. vgui::SETUP_PANEL( this );
  1118. SetKeyBoardInputEnabled( true );
  1119. SetMouseInputEnabled( true );
  1120. m_pChatInput->SetVisible( true );
  1121. vgui::surface()->CalculateMouseVisible();
  1122. m_pChatInput->RequestFocus();
  1123. m_pChatInput->SetPaintBorderEnabled( true );
  1124. m_pChatInput->SetMouseInputEnabled( true );
  1125. // Place the mouse cursor near the text so people notice it.
  1126. int x, y, w, h;
  1127. GetChatHistory()->GetBounds( x, y, w, h );
  1128. #ifndef INFESTED_DLL
  1129. vgui::input()->SetCursorPos( x + ( w/2), y + ( h/2) );
  1130. #endif
  1131. m_pFilterPanel->SetVisible( false );
  1132. }
  1133. m_flHistoryFadeTime = gpGlobals->curtime + CHAT_HISTORY_FADE_TIME;
  1134. engine->ClientCmd_Unrestricted( "gameui_preventescapetoshow\n" );
  1135. }
  1136. //-----------------------------------------------------------------------------
  1137. // Purpose:
  1138. //-----------------------------------------------------------------------------
  1139. void CBaseHudChat::SetChatPrompt( int iMessageModeType )
  1140. {
  1141. if ( m_nMessageMode == MM_SAY )
  1142. {
  1143. m_pChatInput->SetPrompt( g_pVGuiLocalize->FindSafe( "#chat_say" ) );
  1144. }
  1145. else
  1146. {
  1147. m_pChatInput->SetPrompt( g_pVGuiLocalize->FindSafe( "#chat_say_team" ) );
  1148. }
  1149. }
  1150. //-----------------------------------------------------------------------------
  1151. // Purpose:
  1152. //-----------------------------------------------------------------------------
  1153. void CBaseHudChat::StopMessageMode( bool bFade )
  1154. {
  1155. engine->ClientCmd_Unrestricted( "gameui_allowescapetoshow\n" );
  1156. if ( !IsGameConsole() )
  1157. {
  1158. SetKeyBoardInputEnabled( false );
  1159. SetMouseInputEnabled( false );
  1160. if ( GetChatHistory() )
  1161. {
  1162. GetChatHistory()->SetPaintBorderEnabled( false );
  1163. GetChatHistory()->GotoTextEnd();
  1164. GetChatHistory()->SetMouseInputEnabled( false );
  1165. GetChatHistory()->SetVerticalScrollbar( false );
  1166. GetChatHistory()->ResetAllFades( false, true, CHAT_HISTORY_FADE_TIME );
  1167. GetChatHistory()->SelectNoText();
  1168. }
  1169. // Clear the entry since we wont need it anymore.
  1170. m_pChatInput->ClearEntry();
  1171. }
  1172. m_nMessageMode = MM_NONE; // TERROR
  1173. cl_chat_active.SetValue( m_nMessageMode );
  1174. if ( bFade )
  1175. {
  1176. m_flHistoryFadeTime = gpGlobals->curtime + CHAT_HISTORY_FADE_TIME;
  1177. }
  1178. else
  1179. {
  1180. m_flHistoryFadeTime = gpGlobals->curtime;
  1181. if ( IsGameConsole() )
  1182. {
  1183. // console forces these off now
  1184. GetChatHistory()->ResetAllFades( false, false, 0 );
  1185. }
  1186. }
  1187. }
  1188. void CBaseHudChat::FadeChatHistory( void )
  1189. {
  1190. if ( IsGameConsole() )
  1191. {
  1192. return;
  1193. }
  1194. float frac = ( m_flHistoryFadeTime - gpGlobals->curtime ) * CHAT_HISTORY_ONE_OVER_FADE_TIME;
  1195. int alpha = frac * CHAT_HISTORY_ALPHA;
  1196. alpha = clamp( alpha, 0, CHAT_HISTORY_ALPHA );
  1197. if ( alpha >= 0 )
  1198. {
  1199. if ( GetChatHistory() )
  1200. {
  1201. if ( IsMouseInputEnabled() )
  1202. {
  1203. // fade in
  1204. SetAlpha( 255 );
  1205. GetChatHistory()->SetBgColor( Color( 0, 0, 0, CHAT_HISTORY_ALPHA - alpha ) );
  1206. SetBgColor( Color( GetBgColor().r(), GetBgColor().g(), GetBgColor().b(), CHAT_HISTORY_ALPHA - alpha ) );
  1207. m_pChatInput->GetPrompt()->SetAlpha( ( CHAT_HISTORY_ALPHA*2) - alpha );
  1208. m_pChatInput->GetInputPanel()->SetAlpha( ( CHAT_HISTORY_ALPHA*2) - alpha );
  1209. m_pFiltersButton->SetAlpha( ( CHAT_HISTORY_ALPHA*2) - alpha );
  1210. }
  1211. else
  1212. {
  1213. // fade out
  1214. GetChatHistory()->SetBgColor( Color( 0, 0, 0, alpha ) );
  1215. SetBgColor( Color( GetBgColor().r(), GetBgColor().g(), GetBgColor().b(), alpha ) );
  1216. m_pChatInput->GetPrompt()->SetAlpha( alpha );
  1217. m_pChatInput->GetInputPanel()->SetAlpha( alpha );
  1218. m_pFiltersButton->SetAlpha( alpha );
  1219. }
  1220. }
  1221. }
  1222. }
  1223. void CBaseHudChat::SetFilterFlag( int iFilter )
  1224. {
  1225. m_iFilterFlags = iFilter;
  1226. cl_chatfilters.SetValue( m_iFilterFlags );
  1227. }
  1228. //-----------------------------------------------------------------------------
  1229. // Purpose:
  1230. //-----------------------------------------------------------------------------
  1231. Color CBaseHudChat::GetTextColorForClient( TextColor colorNum, int clientIndex )
  1232. {
  1233. Color c;
  1234. switch ( colorNum )
  1235. {
  1236. case COLOR_PLAYERNAME:
  1237. c = GetClientColor( clientIndex );
  1238. break;
  1239. case COLOR_LOCATION:
  1240. c = g_ColorDarkGreen;
  1241. break;
  1242. case COLOR_ACHIEVEMENT:
  1243. {
  1244. vgui::IScheme *pSourceScheme = vgui::scheme()->GetIScheme( vgui::scheme()->GetScheme( "SourceScheme" ) );
  1245. if ( pSourceScheme )
  1246. {
  1247. c = pSourceScheme->GetColor( "SteamLightGreen", GetBgColor() );
  1248. }
  1249. else
  1250. {
  1251. c = GetDefaultTextColor();
  1252. }
  1253. }
  1254. break;
  1255. default:
  1256. c = GetDefaultTextColor();
  1257. }
  1258. return Color( c[0], c[1], c[2], 255 );
  1259. }
  1260. //-----------------------------------------------------------------------------
  1261. Color CBaseHudChat::GetDefaultTextColor( void )
  1262. {
  1263. return g_ColorYellow;
  1264. }
  1265. //-----------------------------------------------------------------------------
  1266. Color CBaseHudChat::GetClientColor( int clientIndex )
  1267. {
  1268. if ( clientIndex == 0 ) // console msg
  1269. {
  1270. return g_ColorGreen;
  1271. }
  1272. else if( g_PR )
  1273. {
  1274. return g_ColorGrey;
  1275. }
  1276. return g_ColorYellow;
  1277. }
  1278. //-----------------------------------------------------------------------------
  1279. // Purpose: Parses a line of text for color markup and inserts it via Colorize()
  1280. //-----------------------------------------------------------------------------
  1281. void CBaseHudChatLine::InsertAndColorizeText( wchar_t *buf, int clientIndex )
  1282. {
  1283. if ( m_text )
  1284. {
  1285. delete[] m_text;
  1286. m_text = NULL;
  1287. }
  1288. m_textRanges.RemoveAll();
  1289. m_text = CloneWString( buf );
  1290. CBaseHudChat *pChat = dynamic_cast<CBaseHudChat*>( GetParent() );
  1291. if ( pChat == NULL )
  1292. return;
  1293. wchar_t *txt = m_text;
  1294. int lineLen = wcslen( m_text );
  1295. if ( m_text[0] == COLOR_PLAYERNAME || m_text[0] == COLOR_LOCATION || m_text[0] == COLOR_NORMAL || m_text[0] == COLOR_ACHIEVEMENT || m_text[0] == COLOR_AWARD || m_text[0] == COLOR_PENALTY )
  1296. {
  1297. while ( txt && *txt )
  1298. {
  1299. TextRange range;
  1300. switch ( *txt )
  1301. {
  1302. case COLOR_PLAYERNAME:
  1303. case COLOR_LOCATION:
  1304. case COLOR_ACHIEVEMENT:
  1305. case COLOR_NORMAL:
  1306. case COLOR_AWARD:
  1307. case COLOR_PENALTY:
  1308. {
  1309. // save this start
  1310. range.start = ( txt-m_text) + 1;
  1311. range.color = pChat->GetTextColorForClient( ( TextColor)( *txt), clientIndex );
  1312. range.end = lineLen;
  1313. int count = m_textRanges.Count();
  1314. if ( count )
  1315. {
  1316. m_textRanges[count-1].end = range.start - 1;
  1317. }
  1318. m_textRanges.AddToTail( range );
  1319. }
  1320. ++txt;
  1321. break;
  1322. default:
  1323. ++txt;
  1324. }
  1325. }
  1326. }
  1327. if ( !m_textRanges.Count() && m_iNameLength > 0 && m_text[0] == COLOR_USEOLDCOLORS )
  1328. {
  1329. TextRange range;
  1330. range.start = 0;
  1331. range.end = m_iNameStart;
  1332. range.color = pChat->GetTextColorForClient( COLOR_NORMAL, clientIndex );
  1333. m_textRanges.AddToTail( range );
  1334. range.start = m_iNameStart;
  1335. range.end = m_iNameStart + m_iNameLength;
  1336. range.color = pChat->GetTextColorForClient( COLOR_PLAYERNAME, clientIndex );
  1337. m_textRanges.AddToTail( range );
  1338. range.start = range.end;
  1339. range.end = wcslen( m_text );
  1340. range.color = pChat->GetTextColorForClient( COLOR_NORMAL, clientIndex );
  1341. m_textRanges.AddToTail( range );
  1342. }
  1343. if ( !m_textRanges.Count() )
  1344. {
  1345. TextRange range;
  1346. range.start = 0;
  1347. range.end = wcslen( m_text );
  1348. range.color = pChat->GetTextColorForClient( COLOR_NORMAL, clientIndex );
  1349. m_textRanges.AddToTail( range );
  1350. }
  1351. for ( int i=0; i<m_textRanges.Count(); ++i )
  1352. {
  1353. wchar_t * start = m_text + m_textRanges[i].start;
  1354. if ( *start > 0 && *start < COLOR_MAX )
  1355. {
  1356. m_textRanges[i].start += 1;
  1357. }
  1358. }
  1359. Colorize();
  1360. }
  1361. //-----------------------------------------------------------------------------
  1362. // Purpose: Inserts colored text into the RichText control at the given alpha
  1363. //-----------------------------------------------------------------------------
  1364. void CBaseHudChatLine::Colorize( int alpha )
  1365. {
  1366. MEM_ALLOC_CREDIT();
  1367. // clear out text
  1368. SetText( "" );
  1369. CBaseHudChat *pChat = dynamic_cast<CBaseHudChat*>( GetParent() );
  1370. if ( pChat && pChat->GetChatHistory() )
  1371. {
  1372. pChat->GetChatHistory()->InsertString( "\n" );
  1373. }
  1374. wchar_t wText[4096];
  1375. Color color;
  1376. for ( int i=0; i<m_textRanges.Count(); ++i )
  1377. {
  1378. wchar_t * start = m_text + m_textRanges[i].start;
  1379. int len = m_textRanges[i].end - m_textRanges[i].start + 1;
  1380. if ( len > 1 )
  1381. {
  1382. wcsncpy( wText, start, len );
  1383. wText[len-1] = 0;
  1384. color = m_textRanges[i].color;
  1385. color[3] = alpha;
  1386. InsertColorChange( color );
  1387. InsertString( wText );
  1388. // TERROR: color console echo
  1389. ConColorMsg( color, "%ls", wText );
  1390. CBaseHudChat *pChat = dynamic_cast<CBaseHudChat*>( GetParent() );
  1391. if ( pChat && pChat->GetChatHistory() )
  1392. {
  1393. pChat->GetChatHistory()->InsertColorChange( color );
  1394. pChat->GetChatHistory()->InsertString( wText );
  1395. pChat->GetChatHistory()->InsertFade( hud_saytext_time.GetFloat(), CHAT_HISTORY_IDLE_FADE_TIME );
  1396. if ( i == m_textRanges.Count()-1 )
  1397. {
  1398. pChat->GetChatHistory()->InsertFade( -1, -1 );
  1399. }
  1400. }
  1401. }
  1402. }
  1403. Msg( "\n" );
  1404. InvalidateLayout( true );
  1405. }
  1406. //-----------------------------------------------------------------------------
  1407. // Purpose:
  1408. // Output : CBaseHudChatLine
  1409. //-----------------------------------------------------------------------------
  1410. CBaseHudChatLine *CBaseHudChat::FindUnusedChatLine( void )
  1411. {
  1412. return m_ChatLine;
  1413. }
  1414. void CBaseHudChat::Send( void )
  1415. {
  1416. if ( IsGameConsole() )
  1417. {
  1418. // not used
  1419. return;
  1420. }
  1421. wchar_t szTextbuf[1024];
  1422. m_pChatInput->GetMessageText( szTextbuf, sizeof( szTextbuf ) );
  1423. char ansi[1024];
  1424. g_pVGuiLocalize->ConvertUnicodeToANSI( szTextbuf, ansi, sizeof( ansi ) );
  1425. int len = Q_strlen( ansi);
  1426. // Remove this code before shipping
  1427. if ( StringHasPrefix( ansi, "bug!" ) || StringHasPrefix( ansi, "bug:" ) )
  1428. {
  1429. char szTempStr[1024];
  1430. char szCommand[1024];
  1431. // Copy the string since we are going to hack it up in ParseTokens
  1432. V_strncpy( szTempStr, ansi+4, sizeof( szTempStr));
  1433. // Auto submit if there is text after the keyword
  1434. // otherwise throw up the bug reporter ui
  1435. CUtlLinkedList<const char *> *tokens = ParseTokens( szTempStr);
  1436. if ( V_strlen( szTempStr))
  1437. {
  1438. V_snprintf( szCommand, sizeof( szCommand), "bug -auto -title \"%s\"", szTempStr);
  1439. }
  1440. else
  1441. {
  1442. V_strncpy( szCommand, "bug", sizeof( szCommand));
  1443. }
  1444. FOR_EACH_LL( (*tokens), i)
  1445. {
  1446. V_snprintf( szCommand, sizeof( szCommand), "%s \"%s\"", szCommand, tokens->Element( i));
  1447. }
  1448. free( tokens);
  1449. //Msg( "BUG: %s\n", szCommand);
  1450. engine->ClientCmd_Unrestricted( szCommand);
  1451. }
  1452. // remove the \n
  1453. if ( len > 0 &&
  1454. ansi[ len - 1 ] == '\n' )
  1455. {
  1456. ansi[ len - 1 ] = '\0';
  1457. }
  1458. if ( len > 0 )
  1459. {
  1460. char szbuf[1024]; // more than 128
  1461. Q_snprintf( szbuf, sizeof( szbuf), "%s \"%s\"", m_nMessageMode == MM_SAY ? "say" : "say_team", ansi );
  1462. engine->ClientCmd_Unrestricted( szbuf);
  1463. }
  1464. m_pChatInput->ClearEntry();
  1465. m_nMessageMode = MM_NONE; // TERROR
  1466. cl_chat_active.SetValue( m_nMessageMode );
  1467. }
  1468. //-----------------------------------------------------------------------------
  1469. // Purpose:
  1470. // Output : vgui::Panel
  1471. //-----------------------------------------------------------------------------
  1472. vgui::Panel *CBaseHudChat::GetInputPanel( void )
  1473. {
  1474. return m_pChatInput->GetInputPanel();
  1475. }
  1476. //-----------------------------------------------------------------------------
  1477. // Purpose:
  1478. //-----------------------------------------------------------------------------
  1479. void CBaseHudChat::Clear( void )
  1480. {
  1481. // Kill input prompt
  1482. StopMessageMode();
  1483. m_flHistoryFadeTime = 0;
  1484. if ( GetChatHistory() )
  1485. {
  1486. GetChatHistory()->ResetAllFades( false, false, 0.0f );
  1487. }
  1488. }
  1489. //-----------------------------------------------------------------------------
  1490. // Purpose:
  1491. // Input : *newmap -
  1492. //-----------------------------------------------------------------------------
  1493. void CBaseHudChat::LevelInit( const char *newmap )
  1494. {
  1495. Clear();
  1496. // [pfreese] initialize new chat filters to defaults. We do this because
  1497. // unused filter bits are zero, and we might want them on for new filters that
  1498. // are added.
  1499. //
  1500. // Also, we have to do this here instead of somewhere more sensible like the
  1501. // c'tor or Init() method, because cvars are currently loaded twice: once
  1502. // during initialization from the local file, and later ( after HUD elements
  1503. // have been construction and initialized) from Steam Cloud remote storage.
  1504. switch ( cl_chatfilter_version.GetInt() )
  1505. {
  1506. case 0:
  1507. m_iFilterFlags |= CHAT_FILTER_ACHIEVEMENT;
  1508. // fall through
  1509. case kChatFilterVersion:
  1510. break;
  1511. }
  1512. if ( cl_chatfilter_version.GetInt() != kChatFilterVersion )
  1513. {
  1514. cl_chatfilters.SetValue( m_iFilterFlags );
  1515. cl_chatfilter_version.SetValue( kChatFilterVersion );
  1516. }
  1517. }
  1518. void CBaseHudChat::LevelShutdown( void )
  1519. {
  1520. Clear();
  1521. }
  1522. void CBaseHudChat::ChatPrintfW( int iPlayerIndex, int iFilter, const wchar_t *wszNotice )
  1523. {
  1524. #if defined( _PS3 ) && !defined( NO_STEAM )
  1525. if ( !steamapicontext->SteamFriends() || steamapicontext->SteamFriends()->GetUserRestrictions() )
  1526. return; // user not eligible to chat
  1527. #endif
  1528. if ( CDemoPlaybackParameters_t const *pParameters = engine->GetDemoPlaybackParameters() )
  1529. {
  1530. if ( pParameters->m_bAnonymousPlayerIdentity )
  1531. return; // cannot print potentially personal details
  1532. }
  1533. // Forward message to Scaleform for display
  1534. #if defined( CSTRIKE15 )
  1535. if ( iFilter != CHAT_FILTER_NONE )
  1536. {
  1537. if ( !( iFilter & GetFilterFlags() ) )
  1538. return;
  1539. }
  1540. CS15ForwardStatusMsg( wszNotice, iPlayerIndex );
  1541. return;
  1542. #else
  1543. Assert( 0 );
  1544. #endif // CSTRIKE15
  1545. }
  1546. //-----------------------------------------------------------------------------
  1547. // Purpose:
  1548. // Input : *fmt -
  1549. // ... -
  1550. //-----------------------------------------------------------------------------
  1551. void CBaseHudChat::ChatPrintf( int iPlayerIndex, int iFilter, const char *fmt, ... )
  1552. {
  1553. #if defined( _PS3 ) && !defined( NO_STEAM )
  1554. if ( !steamapicontext->SteamFriends() || steamapicontext->SteamFriends()->GetUserRestrictions() )
  1555. return; // user not eligible to chat
  1556. #endif
  1557. if ( CDemoPlaybackParameters_t const *pParameters = engine->GetDemoPlaybackParameters() )
  1558. {
  1559. if ( pParameters->m_bAnonymousPlayerIdentity )
  1560. return; // cannot print potentially personal details
  1561. }
  1562. va_list marker;
  1563. char msg[4096];
  1564. va_start( marker, fmt);
  1565. Q_vsnprintf( msg, sizeof( msg), fmt, marker);
  1566. va_end( marker);
  1567. // Strip any trailing '\n'
  1568. if ( strlen( msg ) > 0 && msg[ strlen( msg )-1 ] == '\n' )
  1569. {
  1570. msg[ strlen( msg ) - 1 ] = 0;
  1571. }
  1572. // Strip leading \n characters ( or notify/color signifiers ) for empty string check
  1573. char *pmsg = msg;
  1574. while ( *pmsg && ( *pmsg == '\n' || ( *pmsg > 0 && *pmsg < COLOR_MAX ) ) )
  1575. {
  1576. pmsg++;
  1577. }
  1578. if ( !*pmsg )
  1579. return;
  1580. // [jason] Forward message to Scaleform for display
  1581. #if defined( CSTRIKE15 )
  1582. if ( iFilter != CHAT_FILTER_NONE )
  1583. {
  1584. if ( !( iFilter & GetFilterFlags() ) )
  1585. return;
  1586. }
  1587. CS15ForwardStatusMsg( pmsg, iPlayerIndex );
  1588. return;
  1589. #endif // CSTRIKE15
  1590. // Now strip just newlines, since we want the color info for printing
  1591. pmsg = msg;
  1592. while ( *pmsg && ( *pmsg == '\n' ) )
  1593. {
  1594. pmsg++;
  1595. }
  1596. if ( !*pmsg )
  1597. return;
  1598. CBaseHudChatLine *line = ( CBaseHudChatLine *)FindUnusedChatLine();
  1599. if ( !line )
  1600. {
  1601. line = ( CBaseHudChatLine *)FindUnusedChatLine();
  1602. }
  1603. if ( !line )
  1604. {
  1605. return;
  1606. }
  1607. if ( iFilter != CHAT_FILTER_NONE )
  1608. {
  1609. #ifdef PORTAL2
  1610. if ( iFilter & ( CHAT_FILTER_JOINLEAVE | CHAT_FILTER_TEAMCHANGE ) )
  1611. // In Portal 2 we don't want to show join/leave or teamchange messages
  1612. return;
  1613. #endif
  1614. if ( !( iFilter & GetFilterFlags() ) )
  1615. return;
  1616. }
  1617. if ( hudlcd )
  1618. {
  1619. if ( *pmsg < 32 )
  1620. {
  1621. hudlcd->AddChatLine( pmsg + 1 );
  1622. }
  1623. else
  1624. {
  1625. hudlcd->AddChatLine( pmsg );
  1626. }
  1627. }
  1628. line->SetText( "" );
  1629. int iNameStart = 0;
  1630. int iNameLength = 0;
  1631. player_info_t sPlayerInfo;
  1632. if ( iPlayerIndex == 0 )
  1633. {
  1634. Q_memset( &sPlayerInfo, 0, sizeof( player_info_t) );
  1635. Q_strncpy( sPlayerInfo.name, "Console", sizeof( sPlayerInfo.name) );
  1636. }
  1637. else
  1638. {
  1639. engine->GetPlayerInfo( iPlayerIndex, &sPlayerInfo );
  1640. }
  1641. int bufSize = ( strlen( pmsg ) + 1 ) * sizeof( wchar_t);
  1642. wchar_t *wbuf = static_cast<wchar_t *>( stackalloc( bufSize ) );
  1643. if ( wbuf )
  1644. {
  1645. Color clrNameColor = GetClientColor( iPlayerIndex );
  1646. line->SetExpireTime();
  1647. g_pVGuiLocalize->ConvertANSIToUnicode( pmsg, wbuf, bufSize);
  1648. // find the player's name in the unicode string, in case there is no color markup
  1649. const char *pName = sPlayerInfo.name;
  1650. if ( pName )
  1651. {
  1652. wchar_t wideName[MAX_PLAYER_NAME_LENGTH];
  1653. g_pVGuiLocalize->ConvertANSIToUnicode( pName, wideName, sizeof( wideName ) );
  1654. const wchar_t *nameInString = wcsstr( wbuf, wideName );
  1655. if ( nameInString )
  1656. {
  1657. iNameStart = ( nameInString - wbuf);
  1658. iNameLength = wcslen( wideName );
  1659. }
  1660. }
  1661. line->SetVisible( false );
  1662. line->SetNameStart( iNameStart );
  1663. line->SetNameLength( iNameLength );
  1664. line->SetNameColor( clrNameColor );
  1665. line->InsertAndColorizeText( wbuf, iPlayerIndex );
  1666. }
  1667. }
  1668. //-----------------------------------------------------------------------------
  1669. // Purpose:
  1670. //-----------------------------------------------------------------------------
  1671. void CBaseHudChat::FireGameEvent( IGameEvent *event )
  1672. {
  1673. const char *eventname = event->GetName();
  1674. if ( Q_strcmp( "hltv_chat", eventname ) == 0 )
  1675. {
  1676. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
  1677. if ( !player )
  1678. return;
  1679. ChatPrintf( player->entindex(), CHAT_FILTER_NONE, "(GOTV) %s", event->GetString( "text" ) );
  1680. }
  1681. }