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.

532 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "dod_hud_chat.h"
  8. #include "c_dod_player.h"
  9. #include "c_dod_playerresource.h"
  10. #include "hud_macros.h"
  11. #include "text_message.h"
  12. #include "vguicenterprint.h"
  13. #include "vgui/ILocalize.h"
  14. #include "dodoverview.h"
  15. #include <voice_status.h>
  16. #include "menu.h" // for CHudMenu defs
  17. #include "dod_hud_freezepanel.h"
  18. ConVar cl_voicesubtitles( "cl_voicesubtitles", "1", 0, "Enable/disable subtitle printing on voice commands and hand signals." );
  19. Color g_DoDColorGrey( 200, 200, 200, 255 );
  20. #define DOD_MAX_CHAT_LENGTH 128
  21. // Stuff for the Radio Menus
  22. static void voicemenu1_f( void );
  23. static void voicemenu2_f( void );
  24. static void voicemenu3_f( void );
  25. static ConCommand voicemenu1( "voicemenu1", voicemenu1_f, "Opens a voice menu" );
  26. static ConCommand voicemenu2( "voicemenu2", voicemenu2_f, "Opens a voice menu" );
  27. static ConCommand voicemenu3( "voicemenu3", voicemenu3_f, "Opens a voice menu" );
  28. //
  29. //--------------------------------------------------------------
  30. //
  31. // These methods will bring up the radio menus from the client side.
  32. // They mimic the old server commands of the same name, which used
  33. // to require a round-trip causing latency and unreliability in
  34. // menu responses. Only 1 message is sent to the server now which
  35. // includes both the menu name and the selected item. The server
  36. // is never informed that the menu has been displayed.
  37. //
  38. //--------------------------------------------------------------
  39. //
  40. static int g_ActiveVoiceMenu = 0;
  41. void OpenVoiceMenu( int index )
  42. {
  43. // do not show the menu if the player is dead or is an observer
  44. C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer();
  45. if ( !pPlayer )
  46. return;
  47. if ( !pPlayer->IsAlive() || pPlayer->IsObserver() )
  48. return;
  49. CHudMenu *pMenu = (CHudMenu *) gHUD.FindElement( "CHudMenu" );
  50. if ( !pMenu )
  51. return;
  52. // if they hit the key again, close the menu
  53. if ( g_ActiveVoiceMenu == index )
  54. {
  55. pMenu->HideMenu();
  56. g_ActiveVoiceMenu = 0;
  57. return;
  58. }
  59. switch( index )
  60. {
  61. case 1:
  62. case 2:
  63. case 3:
  64. {
  65. char *pszNation;
  66. if( pPlayer->GetTeamNumber() == TEAM_ALLIES )
  67. {
  68. pszNation = "Amer";
  69. }
  70. else
  71. {
  72. pszNation = "Ger";
  73. }
  74. char cMenuNumber = 'A' + index - 1; // map 1,2,3 to A,B,C
  75. char szMenu[128];
  76. Q_snprintf( szMenu, sizeof(szMenu), "#Menu_%sVoice%c", pszNation, cMenuNumber );
  77. pMenu->ShowMenu( szMenu, 0x3FF );
  78. g_ActiveVoiceMenu = index;
  79. }
  80. break;
  81. case 0:
  82. default:
  83. g_ActiveVoiceMenu = 0;
  84. break;
  85. }
  86. }
  87. static void voicemenu1_f( void )
  88. {
  89. OpenVoiceMenu( 1 );
  90. }
  91. static void voicemenu2_f( void )
  92. {
  93. OpenVoiceMenu( 2 );
  94. }
  95. static void voicemenu3_f( void )
  96. {
  97. OpenVoiceMenu( 3 );
  98. }
  99. CON_COMMAND( menuselect, "menuselect" )
  100. {
  101. if ( args.ArgC() < 2 )
  102. return;
  103. int iSlot = atoi( args[1] );
  104. switch( g_ActiveVoiceMenu )
  105. {
  106. case 1: //RadioA
  107. case 2:
  108. case 3:
  109. {
  110. // check for cancel
  111. if( iSlot == 10 )
  112. {
  113. g_ActiveVoiceMenu = 0;
  114. return;
  115. }
  116. // find the voice command index from the menu and slot
  117. int iVoiceCommand = (g_ActiveVoiceMenu-1) * 9 + (iSlot-1);
  118. Assert( iVoiceCommand >= 0 && iVoiceCommand < (3*9) );
  119. // emit a voice command
  120. engine->ClientCmd( g_VoiceCommands[iVoiceCommand].pszCommandName );
  121. }
  122. break;
  123. case 0:
  124. default:
  125. // if we didn't have a menu open, maybe a plugin did. send it on to the server.
  126. const char *cmd = VarArgs( "menuselect %d", iSlot );
  127. engine->ServerCmd( cmd );
  128. break;
  129. }
  130. // reset menu
  131. g_ActiveVoiceMenu = 0;
  132. }
  133. DECLARE_HUDELEMENT( CHudChat );
  134. DECLARE_HUD_MESSAGE( CHudChat, SayText );
  135. DECLARE_HUD_MESSAGE( CHudChat, TextMsg );
  136. DECLARE_HUD_MESSAGE( CHudChat, VoiceSubtitle );
  137. DECLARE_HUD_MESSAGE( CHudChat, HandSignalSubtitle );
  138. //=====================
  139. //CHudChatLine
  140. //=====================
  141. CHudChatLine::CHudChatLine( vgui::Panel *parent, const char *panelName ) : CBaseHudChatLine( parent, panelName )
  142. {
  143. m_text = NULL;
  144. }
  145. void CHudChatLine::ApplySchemeSettings(vgui::IScheme *pScheme)
  146. {
  147. BaseClass::ApplySchemeSettings( pScheme );
  148. }
  149. //=====================
  150. //CHudChatInputLine
  151. //=====================
  152. void CHudChatInputLine::ApplySchemeSettings(vgui::IScheme *pScheme)
  153. {
  154. BaseClass::ApplySchemeSettings(pScheme);
  155. }
  156. //=====================
  157. //CHudChat
  158. //=====================
  159. CHudChat::CHudChat( const char *pElementName ) : BaseClass( pElementName )
  160. {
  161. }
  162. void CHudChat::CreateChatInputLine( void )
  163. {
  164. m_pChatInput = new CHudChatInputLine( this, "ChatInputLine" );
  165. m_pChatInput->SetVisible( false );
  166. }
  167. void CHudChat::CreateChatLines( void )
  168. {
  169. m_ChatLine = new CHudChatLine( this, "ChatLine1" );
  170. m_ChatLine->SetVisible( false );
  171. }
  172. void CHudChat::ApplySchemeSettings( vgui::IScheme *pScheme )
  173. {
  174. BaseClass::ApplySchemeSettings( pScheme );
  175. }
  176. void CHudChat::Init( void )
  177. {
  178. BaseClass::Init();
  179. HOOK_HUD_MESSAGE( CHudChat, SayText );
  180. HOOK_HUD_MESSAGE( CHudChat, TextMsg );
  181. HOOK_HUD_MESSAGE( CHudChat, VoiceSubtitle );
  182. HOOK_HUD_MESSAGE( CHudChat, HandSignalSubtitle );
  183. }
  184. //-----------------------------------------------------------------------------
  185. // Purpose: Overrides base reset to not cancel chat at round restart
  186. //-----------------------------------------------------------------------------
  187. void CHudChat::Reset( void )
  188. {
  189. }
  190. //-----------------------------------------------------------------------------
  191. // Purpose:
  192. // Input : *pszName -
  193. // iSize -
  194. // *pbuf -
  195. //-----------------------------------------------------------------------------
  196. void CHudChat::MsgFunc_SayText( bf_read &msg )
  197. {
  198. // Got message during connection
  199. if ( !g_PR )
  200. return;
  201. char szString[DOD_MAX_CHAT_LENGTH];
  202. int client = msg.ReadByte();
  203. msg.ReadString( szString, sizeof(szString) );
  204. bool bWantsToChat = msg.ReadByte();
  205. if ( GetClientVoiceMgr()->IsPlayerBlocked( client ) )
  206. return;
  207. if ( client > 0 )
  208. GetDODOverview()->PlayerChat( client );
  209. if ( bWantsToChat )
  210. {
  211. int iFilter = CHAT_FILTER_NONE;
  212. if ( client > 0 && (g_PR->GetTeam( client ) != g_PR->GetTeam( GetLocalPlayerIndex() )) )
  213. {
  214. iFilter = CHAT_FILTER_PUBLICCHAT;
  215. }
  216. // Localize any words in the chat that start with #
  217. FindLocalizableSubstrings( szString, sizeof(szString) );
  218. // print raw chat text
  219. ChatPrintf( client, iFilter, "%c%s", COLOR_USEOLDCOLORS, szString );
  220. }
  221. else
  222. {
  223. // try to lookup translated string
  224. Printf( GetFilterForString( szString ), "%s", hudtextmessage->LookupString( szString ) );
  225. }
  226. Msg( "%s", szString );
  227. }
  228. void CHudChat::MsgFunc_VoiceSubtitle( bf_read &msg )
  229. {
  230. // Got message during connection
  231. if ( !g_PR )
  232. return;
  233. if ( !cl_showtextmsg.GetInt() )
  234. return;
  235. if ( !cl_voicesubtitles.GetInt() )
  236. return;
  237. char szString[2048];
  238. char szPrefix[64]; //(Voice)
  239. wchar_t szBuf[128];
  240. int client = msg.ReadByte();
  241. if ( GetClientVoiceMgr()->IsPlayerBlocked( client ) )
  242. return;
  243. if ( client > 0 )
  244. GetDODOverview()->PlayerChat( client );
  245. int iTeam = msg.ReadByte();
  246. int iVoiceCommand = msg.ReadByte();
  247. //Assert( iVoiceCommand <= ARRAYSIZE(g_VoiceCommands) );
  248. Assert( iTeam == TEAM_ALLIES || iTeam == TEAM_AXIS );
  249. const char *pszSubtitle = g_VoiceCommands[iVoiceCommand].pszAlliedSubtitle;
  250. if( iTeam == TEAM_AXIS && g_VoiceCommands[iVoiceCommand].pszAxisSubtitle != NULL )
  251. pszSubtitle = g_VoiceCommands[iVoiceCommand].pszAxisSubtitle;
  252. const wchar_t *pBuf = g_pVGuiLocalize->Find( pszSubtitle );
  253. if ( pBuf )
  254. {
  255. // Copy pBuf into szBuf[i].
  256. int nMaxChars = sizeof( szBuf ) / sizeof( wchar_t );
  257. wcsncpy( szBuf, pBuf, nMaxChars );
  258. szBuf[nMaxChars-1] = 0;
  259. }
  260. else
  261. {
  262. g_pVGuiLocalize->ConvertANSIToUnicode( pszSubtitle, szBuf, sizeof(szBuf) );
  263. }
  264. int len;
  265. g_pVGuiLocalize->ConvertUnicodeToANSI( szBuf, szString, sizeof(szString) );
  266. len = strlen( szString );
  267. if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' )
  268. {
  269. Q_strncat( szString, "\n", sizeof(szString), 1 );
  270. }
  271. const wchar_t *pVoicePrefix = g_pVGuiLocalize->Find( "#Voice" );
  272. g_pVGuiLocalize->ConvertUnicodeToANSI( pVoicePrefix, szPrefix, sizeof(szPrefix) );
  273. ChatPrintf( client, CHAT_FILTER_NONE, "%c(%s) %s%c: %s", COLOR_PLAYERNAME, szPrefix, g_PR->GetPlayerName( client ), COLOR_NORMAL, ConvertCRtoNL( szString ) );
  274. }
  275. void CHudChat::MsgFunc_HandSignalSubtitle( bf_read &msg )
  276. {
  277. // Got message during connection
  278. if ( !g_PR )
  279. return;
  280. if ( !cl_showtextmsg.GetInt() )
  281. return;
  282. if ( !cl_voicesubtitles.GetInt() )
  283. return;
  284. char szString[2048];
  285. char szPrefix[64]; //(HandSignal)
  286. wchar_t szBuf[128];
  287. int client = msg.ReadByte();
  288. int iSignal = msg.ReadByte();
  289. if ( GetClientVoiceMgr()->IsPlayerBlocked( client ) )
  290. return;
  291. if ( client > 0 )
  292. GetDODOverview()->PlayerChat( client );
  293. const char *pszSubtitle = g_HandSignals[iSignal].pszSubtitle;
  294. const wchar_t *pBuf = g_pVGuiLocalize->Find( pszSubtitle );
  295. if ( pBuf )
  296. {
  297. // Copy pBuf into szBuf[i].
  298. int nMaxChars = sizeof( szBuf ) / sizeof( wchar_t );
  299. wcsncpy( szBuf, pBuf, nMaxChars );
  300. szBuf[nMaxChars-1] = 0;
  301. }
  302. else
  303. {
  304. g_pVGuiLocalize->ConvertANSIToUnicode( pszSubtitle, szBuf, sizeof(szBuf) );
  305. }
  306. int len;
  307. g_pVGuiLocalize->ConvertUnicodeToANSI( szBuf, szString, sizeof(szString) );
  308. len = strlen( szString );
  309. if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' )
  310. {
  311. Q_strncat( szString, "\n", sizeof(szString), 1 );
  312. }
  313. const wchar_t *pVoicePrefix = g_pVGuiLocalize->Find( "#HandSignal" );
  314. g_pVGuiLocalize->ConvertUnicodeToANSI( pVoicePrefix, szPrefix, sizeof(szPrefix) );
  315. Assert( g_PR );
  316. ChatPrintf( client, CHAT_FILTER_NONE, "%c(%s) %s%c: %s", COLOR_USEOLDCOLORS, szPrefix, g_PR->GetPlayerName( client ), COLOR_NORMAL, ConvertCRtoNL( szString ) );
  317. }
  318. //-----------------------------------------------------------------------------
  319. // Purpose:
  320. //-----------------------------------------------------------------------------
  321. int CHudChat::GetChatInputOffset( void )
  322. {
  323. if ( m_pChatInput->IsVisible() )
  324. {
  325. return m_iFontHeight;
  326. }
  327. else
  328. {
  329. return 0;
  330. }
  331. }
  332. wchar_t* ReadLocalizedVoiceCommandString( bf_read &msg, wchar_t *pOut, int outSize, bool bStripNewline )
  333. {
  334. char szString[2048];
  335. msg.ReadString( szString, sizeof(szString) );
  336. const wchar_t *pBuf = g_pVGuiLocalize->Find( szString );
  337. if ( pBuf )
  338. {
  339. wcsncpy( pOut, pBuf, outSize/sizeof(wchar_t) );
  340. pOut[outSize/sizeof(wchar_t)-1] = 0;
  341. }
  342. else
  343. {
  344. g_pVGuiLocalize->ConvertANSIToUnicode( szString, pOut, outSize );
  345. }
  346. if ( bStripNewline )
  347. StripEndNewlineFromString( pOut );
  348. return pOut;
  349. }
  350. // Find words in the chat that can be localized and replace them with localized text
  351. void CHudChat::FindLocalizableSubstrings( char *szChat, int chatLength )
  352. {
  353. static char buf[DOD_MAX_CHAT_LENGTH];
  354. buf[0] = '\0';
  355. int pos = 0;
  356. static char szTemp[DOD_MAX_CHAT_LENGTH];
  357. wchar_t *pwcLocalized;
  358. for ( char *pSrc = szChat; pSrc != NULL && *pSrc != 0 && pos < chatLength-1; pSrc++ )
  359. {
  360. // if its a #
  361. if ( *pSrc == '#' )
  362. {
  363. // trim into a word
  364. char *pWord = pSrc;
  365. int iWordPos = 0;
  366. while ( *pWord != ' ' &&
  367. *pWord != '\0' &&
  368. *pWord != '\n' )
  369. {
  370. szTemp[iWordPos] = *pWord;
  371. iWordPos++;
  372. pWord++;
  373. }
  374. szTemp[iWordPos] = '\0';
  375. pwcLocalized = g_pVGuiLocalize->Find( szTemp );
  376. // localize word
  377. if ( pwcLocalized )
  378. {
  379. // print it into the buf
  380. g_pVGuiLocalize->ConvertUnicodeToANSI( pwcLocalized, szTemp, sizeof(szTemp) );
  381. }
  382. // copy the string to chat
  383. buf[pos] = '\0';
  384. Q_strncat( buf, szTemp, DOD_MAX_CHAT_LENGTH, COPY_ALL_CHARACTERS );
  385. int remainingSpace = chatLength - pos - 2; // minus one for the NULL and one for the space
  386. pos += MIN( Q_strlen(szTemp), remainingSpace );
  387. pSrc += iWordPos-1; // progress pSrc to the end of the word
  388. }
  389. else
  390. {
  391. // copy each char across
  392. buf[pos] = *pSrc;
  393. pos++;
  394. }
  395. }
  396. buf[pos] = '\0';
  397. pos++;
  398. //copy buf back to szChat
  399. Q_strncpy( szChat, buf, MIN(chatLength, pos) );
  400. }
  401. Color CHudChat::GetDefaultTextColor( void )
  402. {
  403. return g_DoDColorGrey;
  404. }
  405. Color CHudChat::GetClientColor( int clientIndex )
  406. {
  407. // If player resource is bogus, return some obvious colour
  408. // or if we want a generic colour
  409. if ( !g_PR || clientIndex < 1 )
  410. return GetDefaultTextColor();
  411. return g_PR->GetTeamColor( g_PR->GetTeam( clientIndex ) );
  412. }
  413. //-----------------------------------------------------------------------------
  414. // Purpose:
  415. //-----------------------------------------------------------------------------
  416. bool CHudChat::IsVisible( void )
  417. {
  418. if ( IsTakingAFreezecamScreenshot() )
  419. return false;
  420. return BaseClass::IsVisible();
  421. }