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.

471 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "sdk_hud_chat.h"
  8. //#include "c_sdk_player.h"
  9. //#include "c_sdk_playerresource.h"
  10. #include "hud_macros.h"
  11. #include "text_message.h"
  12. #include "vguicenterprint.h"
  13. #include "vgui/ILocalize.h"
  14. #include "ihudlcd.h"
  15. ConVar cl_showtextmsg( "cl_showtextmsg", "1", 0, "Enable/disable text messages printing on the screen." );
  16. float g_ColorGreen[3] = { 153, 255, 153 };
  17. float g_ColorYellow[3] = { 255, 178.5, 0.0 };
  18. float *GetClientColor( int clientIndex )
  19. {
  20. if ( clientIndex == 0 ) // console msg
  21. {
  22. return g_ColorGreen;
  23. }
  24. else
  25. {
  26. return g_ColorYellow;
  27. }
  28. }
  29. // converts all '\r' characters to '\n', so that the engine can deal with the properly
  30. // returns a pointer to str
  31. static char* ConvertCRtoNL( char *str )
  32. {
  33. for ( char *ch = str; *ch != 0; ch++ )
  34. if ( *ch == '\r' )
  35. *ch = '\n';
  36. return str;
  37. }
  38. // converts all '\r' characters to '\n', so that the engine can deal with the properly
  39. // returns a pointer to str
  40. static wchar_t* ConvertCRtoNL( wchar_t *str )
  41. {
  42. for ( wchar_t *ch = str; *ch != 0; ch++ )
  43. if ( *ch == L'\r' )
  44. *ch = L'\n';
  45. return str;
  46. }
  47. static void StripEndNewlineFromString( char *str )
  48. {
  49. int s = strlen( str ) - 1;
  50. if ( s >= 0 )
  51. {
  52. if ( str[s] == '\n' || str[s] == '\r' )
  53. str[s] = 0;
  54. }
  55. }
  56. static void StripEndNewlineFromString( wchar_t *str )
  57. {
  58. int s = wcslen( str ) - 1;
  59. if ( s >= 0 )
  60. {
  61. if ( str[s] == L'\n' || str[s] == L'\r' )
  62. str[s] = 0;
  63. }
  64. }
  65. DECLARE_HUDELEMENT( CHudChat );
  66. DECLARE_HUD_MESSAGE( CHudChat, SayText );
  67. DECLARE_HUD_MESSAGE( CHudChat, TextMsg );
  68. //=====================
  69. //CHudChatLine
  70. //=====================
  71. void CHudChatLine::ApplySchemeSettings(vgui::IScheme *pScheme)
  72. {
  73. BaseClass::ApplySchemeSettings( pScheme );
  74. m_hFont = pScheme->GetFont( "ChatFont" );
  75. SetBorder( NULL );
  76. SetBgColor( Color( 0, 0, 0, 0 ) );
  77. SetFgColor( Color( 0, 0, 0, 0 ) );
  78. SetFont( m_hFont );
  79. }
  80. void CHudChatLine::PerformFadeout( void )
  81. {
  82. // Flash + Extra bright when new
  83. float curtime = gpGlobals->curtime;
  84. int lr = m_clrText[0];
  85. int lg = m_clrText[1];
  86. int lb = m_clrText[2];
  87. //CSPort chat only fades out, no blinking.
  88. if ( curtime <= m_flExpireTime && curtime > m_flExpireTime - CHATLINE_FADE_TIME )
  89. {
  90. float frac = ( m_flExpireTime - curtime ) / CHATLINE_FADE_TIME;
  91. int alpha = frac * 255;
  92. alpha = clamp( alpha, 0, 255 );
  93. wchar_t wbuf[4096];
  94. GetText(0, wbuf, sizeof(wbuf));
  95. SetText( "" );
  96. if ( m_iNameLength > 0 )
  97. {
  98. wchar_t wText[4096];
  99. // draw the first x characters in the player color
  100. wcsncpy( wText, wbuf, MIN( m_iNameLength + 1, MAX_PLAYER_NAME_LENGTH+32) );
  101. wText[ MIN( m_iNameLength, MAX_PLAYER_NAME_LENGTH+31) ] = 0;
  102. m_clrNameColor[3] = alpha;
  103. InsertColorChange( m_clrNameColor );
  104. InsertString( wText );
  105. wcsncpy( wText, wbuf + ( m_iNameLength ), wcslen( wbuf + m_iNameLength ) );
  106. wText[ wcslen( wbuf + m_iNameLength ) ] = '\0';
  107. InsertColorChange( Color( g_ColorYellow[0], g_ColorYellow[1], g_ColorYellow[2], alpha ) );
  108. InsertString( wText );
  109. InvalidateLayout( true );
  110. }
  111. else
  112. {
  113. InsertColorChange( Color( lr, lg, lb, alpha ) );
  114. InsertString( wbuf );
  115. }
  116. }
  117. OnThink();
  118. }
  119. //=====================
  120. //CHudChatInputLine
  121. //=====================
  122. void CHudChatInputLine::ApplySchemeSettings(vgui::IScheme *pScheme)
  123. {
  124. BaseClass::ApplySchemeSettings(pScheme);
  125. vgui::HFont hFont = pScheme->GetFont( "ChatFont" );
  126. m_pPrompt->SetFont( hFont );
  127. m_pInput->SetFont( hFont );
  128. m_pInput->SetFgColor( pScheme->GetColor( "Chat.TypingText", pScheme->GetColor( "Panel.FgColor", Color( 255, 255, 255, 255 ) ) ) );
  129. }
  130. //=====================
  131. //CHudChat
  132. //=====================
  133. CHudChat::CHudChat( const char *pElementName ) : BaseClass( pElementName )
  134. {
  135. }
  136. void CHudChat::CreateChatInputLine( void )
  137. {
  138. m_pChatInput = new CHudChatInputLine( this, "ChatInputLine" );
  139. m_pChatInput->SetVisible( false );
  140. }
  141. void CHudChat::CreateChatLines( void )
  142. {
  143. for ( int i = 0; i < CHAT_INTERFACE_LINES; i++ )
  144. {
  145. char sz[ 32 ];
  146. Q_snprintf( sz, sizeof( sz ), "ChatLine%02i", i );
  147. m_ChatLines[ i ] = new CHudChatLine( this, sz );
  148. m_ChatLines[ i ]->SetVisible( false );
  149. }
  150. }
  151. void CHudChat::ApplySchemeSettings( vgui::IScheme *pScheme )
  152. {
  153. BaseClass::ApplySchemeSettings( pScheme );
  154. SetBgColor( Color( 0, 0, 0, 0 ) );
  155. SetFgColor( Color( 0, 0, 0, 0 ) );
  156. }
  157. void CHudChat::Init( void )
  158. {
  159. BaseClass::Init();
  160. HOOK_HUD_MESSAGE( CHudChat, SayText );
  161. HOOK_HUD_MESSAGE( CHudChat, TextMsg );
  162. }
  163. //-----------------------------------------------------------------------------
  164. // Purpose: Overrides base reset to not cancel chat at round restart
  165. //-----------------------------------------------------------------------------
  166. void CHudChat::Reset( void )
  167. {
  168. }
  169. //-----------------------------------------------------------------------------
  170. // Purpose:
  171. // Input : *pszName -
  172. // iSize -
  173. // *pbuf -
  174. //-----------------------------------------------------------------------------
  175. void CHudChat::MsgFunc_SayText( bf_read &msg )
  176. {
  177. char szString[256];
  178. int client = msg.ReadByte();
  179. msg.ReadString( szString, sizeof(szString) );
  180. bool bWantsToChat = msg.ReadByte();
  181. if ( bWantsToChat )
  182. {
  183. // print raw chat text
  184. ChatPrintf( client, "%s", szString );
  185. }
  186. else
  187. {
  188. // try to lookup translated string
  189. Printf( "%s", hudtextmessage->LookupString( szString ) );
  190. }
  191. Msg( "%s", szString );
  192. }
  193. wchar_t* ReadLocalizedRadioCommandString( bf_read &msg, wchar_t *pOut, int outSize, bool bStripNewline )
  194. {
  195. char szString[2048];
  196. msg.ReadString( szString, sizeof(szString) );
  197. const wchar_t *pBuf = g_pVGuiLocalize->Find( szString );
  198. if ( pBuf )
  199. {
  200. wcsncpy( pOut, pBuf, outSize/sizeof(wchar_t) );
  201. pOut[outSize/sizeof(wchar_t)-1] = 0;
  202. }
  203. else
  204. {
  205. g_pVGuiLocalize->ConvertANSIToUnicode( szString, pOut, outSize );
  206. }
  207. if ( bStripNewline )
  208. StripEndNewlineFromString( pOut );
  209. return pOut;
  210. }
  211. // Message handler for text messages
  212. // displays a string, looking them up from the titles.txt file, which can be localised
  213. // parameters:
  214. // byte: message direction ( HUD_PRINTCONSOLE, HUD_PRINTNOTIFY, HUD_PRINTCENTER, HUD_PRINTTALK )
  215. // string: message
  216. // optional parameters:
  217. // string: message parameter 1
  218. // string: message parameter 2
  219. // string: message parameter 3
  220. // string: message parameter 4
  221. // any string that starts with the character '#' is a message name, and is used to look up the real message in titles.txt
  222. // the next (optional) one to four strings are parameters for that string (which can also be message names if they begin with '#')
  223. void CHudChat::MsgFunc_TextMsg( bf_read &msg )
  224. {
  225. char szString[2048];
  226. int msg_dest = msg.ReadByte();
  227. wchar_t szBuf[5][128];
  228. wchar_t outputBuf[256];
  229. for ( int i=0; i<5; ++i )
  230. {
  231. msg.ReadString( szString, sizeof(szString) );
  232. char *tmpStr = hudtextmessage->LookupString( szString, &msg_dest );
  233. const wchar_t *pBuf = g_pVGuiLocalize->Find( tmpStr );
  234. if ( pBuf )
  235. {
  236. // Copy pBuf into szBuf[i].
  237. int nMaxChars = sizeof( szBuf[i] ) / sizeof( wchar_t );
  238. wcsncpy( szBuf[i], pBuf, nMaxChars );
  239. szBuf[i][nMaxChars-1] = 0;
  240. }
  241. else
  242. {
  243. if ( i )
  244. {
  245. StripEndNewlineFromString( tmpStr ); // these strings are meant for subsitution into the main strings, so cull the automatic end newlines
  246. }
  247. g_pVGuiLocalize->ConvertANSIToUnicode( tmpStr, szBuf[i], sizeof(szBuf[i]) );
  248. }
  249. }
  250. if ( !cl_showtextmsg.GetInt() )
  251. return;
  252. int len;
  253. switch ( msg_dest )
  254. {
  255. case HUD_PRINTCENTER:
  256. g_pVGuiLocalize->ConstructString( outputBuf, sizeof(outputBuf), szBuf[0], 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] );
  257. internalCenterPrint->Print( ConvertCRtoNL( outputBuf ) );
  258. break;
  259. case HUD_PRINTNOTIFY:
  260. g_pVGuiLocalize->ConstructString( outputBuf, sizeof(outputBuf), szBuf[0], 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] );
  261. g_pVGuiLocalize->ConvertUnicodeToANSI( outputBuf, szString, sizeof(szString) );
  262. len = strlen( szString );
  263. if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' )
  264. {
  265. Q_strncat( szString, "\n", sizeof(szString), 1 );
  266. }
  267. Msg( "%s", ConvertCRtoNL( szString ) );
  268. break;
  269. case HUD_PRINTTALK:
  270. g_pVGuiLocalize->ConstructString( outputBuf, sizeof(outputBuf), szBuf[0], 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] );
  271. g_pVGuiLocalize->ConvertUnicodeToANSI( outputBuf, szString, sizeof(szString) );
  272. len = strlen( szString );
  273. if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' )
  274. {
  275. Q_strncat( szString, "\n", sizeof(szString), 1 );
  276. }
  277. Printf( "%s", ConvertCRtoNL( szString ) );
  278. break;
  279. case HUD_PRINTCONSOLE:
  280. g_pVGuiLocalize->ConstructString( outputBuf, sizeof(outputBuf), szBuf[0], 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] );
  281. g_pVGuiLocalize->ConvertUnicodeToANSI( outputBuf, szString, sizeof(szString) );
  282. len = strlen( szString );
  283. if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' )
  284. {
  285. Q_strncat( szString, "\n", sizeof(szString), 1 );
  286. }
  287. Msg( "%s", ConvertCRtoNL( szString ) );
  288. break;
  289. }
  290. }
  291. //-----------------------------------------------------------------------------
  292. // Purpose:
  293. // Input : *fmt -
  294. // ... -
  295. //-----------------------------------------------------------------------------
  296. void CHudChat::ChatPrintf( int iPlayerIndex, const char *fmt, ... )
  297. {
  298. va_list marker;
  299. char msg[4096];
  300. va_start(marker, fmt);
  301. Q_vsnprintf(msg, sizeof( msg), fmt, marker);
  302. va_end(marker);
  303. // Strip any trailing '\n'
  304. if ( strlen( msg ) > 0 && msg[ strlen( msg )-1 ] == '\n' )
  305. {
  306. msg[ strlen( msg ) - 1 ] = 0;
  307. }
  308. // Strip leading \n characters ( or notify/color signifiers )
  309. char *pmsg = msg;
  310. while ( *pmsg && ( *pmsg == '\n' || *pmsg == 1 || *pmsg == 2 ) )
  311. {
  312. pmsg++;
  313. }
  314. if ( !*pmsg )
  315. return;
  316. if ( *pmsg < 32 )
  317. {
  318. hudlcd->AddChatLine( pmsg + 1 );
  319. }
  320. else
  321. {
  322. hudlcd->AddChatLine( pmsg );
  323. }
  324. CHudChatLine *line = (CHudChatLine *)FindUnusedChatLine();
  325. if ( !line )
  326. {
  327. ExpireOldest();
  328. line = (CHudChatLine *)FindUnusedChatLine();
  329. }
  330. if ( !line )
  331. {
  332. return;
  333. }
  334. line->SetText( "" );
  335. int iNameLength = 0;
  336. player_info_t sPlayerInfo;
  337. if ( iPlayerIndex == 0 )
  338. {
  339. Q_memset( &sPlayerInfo, 0, sizeof(player_info_t) );
  340. Q_strncpy( sPlayerInfo.name, "Console", sizeof(sPlayerInfo.name) );
  341. }
  342. else
  343. {
  344. engine->GetPlayerInfo( iPlayerIndex, &sPlayerInfo );
  345. }
  346. const char *pName = sPlayerInfo.name;
  347. if ( pName )
  348. {
  349. const char *nameInString = strstr( pmsg, pName );
  350. if ( nameInString )
  351. {
  352. iNameLength = strlen( pName ) + (nameInString - pmsg);
  353. }
  354. }
  355. else
  356. line->InsertColorChange( Color( g_ColorYellow[0], g_ColorYellow[1], g_ColorYellow[2], 255 ) );
  357. char *buf = static_cast<char *>( _alloca( strlen( pmsg ) + 1 ) );
  358. wchar_t *wbuf = static_cast<wchar_t *>( _alloca( (strlen( pmsg ) + 1 ) * sizeof(wchar_t) ) );
  359. if ( buf )
  360. {
  361. float *flColor = GetClientColor( iPlayerIndex );
  362. line->SetExpireTime();
  363. // draw the first x characters in the player color
  364. Q_strncpy( buf, pmsg, MIN( iNameLength + 1, MAX_PLAYER_NAME_LENGTH+32) );
  365. buf[ MIN( iNameLength, MAX_PLAYER_NAME_LENGTH+31) ] = 0;
  366. line->InsertColorChange( Color( flColor[0], flColor[1], flColor[2], 255 ) );
  367. line->InsertString( buf );
  368. Q_strncpy( buf, pmsg + iNameLength, strlen( pmsg ));
  369. buf[ strlen( pmsg + iNameLength ) ] = '\0';
  370. line->InsertColorChange( Color( g_ColorYellow[0], g_ColorYellow[1], g_ColorYellow[2], 255 ) );
  371. g_pVGuiLocalize->ConvertANSIToUnicode( buf, wbuf, strlen(pmsg)*sizeof(wchar_t));
  372. line->InsertString( wbuf );
  373. line->SetVisible( true );
  374. line->SetNameLength( iNameLength );
  375. line->SetNameColor( Color( flColor[0], flColor[1], flColor[2], 255 ) );
  376. }
  377. CLocalPlayerFilter filter;
  378. C_BaseEntity::EmitSound( filter, -1 /*SOUND_FROM_LOCAL_PLAYER*/, "HudChat.Message" );
  379. }
  380. int CHudChat::GetChatInputOffset( void )
  381. {
  382. if ( m_pChatInput->IsVisible() )
  383. {
  384. return m_iFontHeight;
  385. }
  386. else
  387. return 0;
  388. }