Team Fortress 2 Source Code as on 22/4/2020
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.

1838 lines
47 KiB

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