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.

906 lines
25 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include <cdll_client_int.h>
  9. #include <globalvars_base.h>
  10. #include <cdll_util.h>
  11. #include <KeyValues.h>
  12. #include "spectatorgui.h"
  13. #include <vgui/IScheme.h>
  14. #include <vgui/ILocalize.h>
  15. #include <vgui/ISurface.h>
  16. #include <vgui/IPanel.h>
  17. #include <vgui_controls/ImageList.h>
  18. #include <vgui_controls/MenuItem.h>
  19. #include <vgui_controls/TextImage.h>
  20. #include <stdio.h> // _snprintf define
  21. #include <game/client/iviewport.h>
  22. #include "commandmenu.h"
  23. #include "hltvcamera.h"
  24. #if defined( REPLAY_ENABLED )
  25. #include "replaycamera.h"
  26. #endif
  27. #include <vgui_controls/TextEntry.h>
  28. #include <vgui_controls/Panel.h>
  29. #include <vgui_controls/ImagePanel.h>
  30. #include <vgui_controls/Menu.h>
  31. #include "IGameUIFuncs.h" // for key bindings
  32. #include <imapoverview.h>
  33. #include <shareddefs.h>
  34. #include <igameresources.h>
  35. // memdbgon must be the last include file in a .cpp file!!!
  36. #include "tier0/memdbgon.h"
  37. extern IGameUIFuncs *gameuifuncs; // for key binding details
  38. // void DuckMessage(const char *str); // from vgui_teamfortressviewport.cpp
  39. ConVar spec_scoreboard( "spec_scoreboard", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
  40. CSpectatorGUI *g_pSpectatorGUI = NULL;
  41. // NB disconnect between localization text and observer mode enums
  42. static char *s_SpectatorModes[] =
  43. {
  44. "#Spec_Mode0", // OBS_MODE_NONE = 0,
  45. "#Spec_Mode1", // OBS_MODE_DEATHCAM,
  46. "", // OBS_MODE_FREEZECAM,
  47. "#Spec_Mode2", // OBS_MODE_FIXED,
  48. "#Spec_Mode3", // OBS_MODE_IN_EYE,
  49. "#Spec_Mode4", // OBS_MODE_CHASE,
  50. "#Spec_Mode5", // OBS_MODE_ROAMING,
  51. };
  52. using namespace vgui;
  53. ConVar cl_spec_mode(
  54. "cl_spec_mode",
  55. "1",
  56. FCVAR_ARCHIVE | FCVAR_USERINFO | FCVAR_SERVER_CAN_EXECUTE,
  57. "spectator mode" );
  58. //-----------------------------------------------------------------------------
  59. // Purpose: left and right buttons pointing buttons
  60. //-----------------------------------------------------------------------------
  61. class CSpecButton : public Button
  62. {
  63. public:
  64. CSpecButton(Panel *parent, const char *panelName): Button(parent, panelName, "") {}
  65. private:
  66. void ApplySchemeSettings(vgui::IScheme *pScheme)
  67. {
  68. Button::ApplySchemeSettings(pScheme);
  69. SetFont(pScheme->GetFont("Marlett", IsProportional()) );
  70. }
  71. };
  72. //-----------------------------------------------------------------------------
  73. // Purpose: Constructor
  74. //-----------------------------------------------------------------------------
  75. CSpectatorMenu::CSpectatorMenu( IViewPort *pViewPort ) : BaseClass( NULL, PANEL_SPECMENU )
  76. {
  77. m_iDuckKey = BUTTON_CODE_INVALID;
  78. m_pViewPort = pViewPort;
  79. SetMouseInputEnabled( true );
  80. SetKeyBoardInputEnabled( true );
  81. SetTitleBarVisible( false ); // don't draw a title bar
  82. SetMoveable( false );
  83. SetSizeable( false );
  84. SetProportional(true);
  85. SetScheme("ClientScheme");
  86. m_pPlayerList = new ComboBox(this, "playercombo", 10 , false);
  87. HFont hFallbackFont = scheme()->GetIScheme( GetScheme() )->GetFont( "DefaultVerySmallFallBack", false );
  88. if ( INVALID_FONT != hFallbackFont )
  89. {
  90. m_pPlayerList->SetUseFallbackFont( true, hFallbackFont );
  91. }
  92. m_pViewOptions = new ComboBox(this, "viewcombo", 10 , false );
  93. m_pConfigSettings = new ComboBox(this, "settingscombo", 10 , false );
  94. m_pLeftButton = new CSpecButton( this, "specprev");
  95. m_pLeftButton->SetText("3");
  96. m_pRightButton = new CSpecButton( this, "specnext");
  97. m_pRightButton->SetText("4");
  98. m_pPlayerList->SetText("");
  99. m_pViewOptions->SetText("#Spec_Modes");
  100. m_pConfigSettings->SetText("#Spec_Options");
  101. m_pPlayerList->SetOpenDirection( Menu::UP );
  102. m_pViewOptions->SetOpenDirection( Menu::UP );
  103. m_pConfigSettings->SetOpenDirection( Menu::UP );
  104. // create view config menu
  105. CommandMenu * menu = new CommandMenu(m_pConfigSettings, "spectatormenu", GetViewPortInterface());
  106. menu->LoadFromFile( "Resource/spectatormenu.res" );
  107. m_pConfigSettings->SetMenu( menu ); // attach menu to combo box
  108. // create view mode menu
  109. menu = new CommandMenu(m_pViewOptions, "spectatormodes", GetViewPortInterface());
  110. menu->LoadFromFile("Resource/spectatormodes.res");
  111. m_pViewOptions->SetMenu( menu ); // attach menu to combo box
  112. LoadControlSettings("Resource/UI/BottomSpectator.res");
  113. ListenForGameEvent( "spec_target_updated" );
  114. }
  115. void CSpectatorMenu::ApplySchemeSettings(IScheme *pScheme)
  116. {
  117. BaseClass::ApplySchemeSettings(pScheme);
  118. // need to MakeReadyForUse() on the menus so we can set their bg color before they are displayed
  119. m_pConfigSettings->GetMenu()->MakeReadyForUse();
  120. m_pViewOptions->GetMenu()->MakeReadyForUse();
  121. m_pPlayerList->GetMenu()->MakeReadyForUse();
  122. if ( g_pSpectatorGUI )
  123. {
  124. m_pConfigSettings->GetMenu()->SetBgColor( g_pSpectatorGUI->GetBlackBarColor() );
  125. m_pViewOptions->GetMenu()->SetBgColor( g_pSpectatorGUI->GetBlackBarColor() );
  126. m_pPlayerList->GetMenu()->SetBgColor( g_pSpectatorGUI->GetBlackBarColor() );
  127. }
  128. }
  129. //-----------------------------------------------------------------------------
  130. // Purpose: makes the GUI fill the screen
  131. //-----------------------------------------------------------------------------
  132. void CSpectatorMenu::PerformLayout()
  133. {
  134. int w,h;
  135. GetHudSize(w, h);
  136. // fill the screen
  137. SetSize(w,GetTall());
  138. }
  139. //-----------------------------------------------------------------------------
  140. // Purpose: Handles changes to combo boxes
  141. //-----------------------------------------------------------------------------
  142. void CSpectatorMenu::OnTextChanged(KeyValues *data)
  143. {
  144. Panel *panel = reinterpret_cast<vgui::Panel *>( data->GetPtr("panel") );
  145. vgui::ComboBox *box = dynamic_cast<vgui::ComboBox *>( panel );
  146. if( box == m_pConfigSettings) // don't change the text in the config setting combo
  147. {
  148. m_pConfigSettings->SetText("#Spec_Options");
  149. }
  150. else if ( box == m_pPlayerList )
  151. {
  152. KeyValues *kv = box->GetActiveItemUserData();
  153. if ( kv && GameResources() )
  154. {
  155. const char *player = kv->GetString("player");
  156. int currentPlayerNum = GetSpectatorTarget();
  157. const char *currentPlayerName = GameResources()->GetPlayerName( currentPlayerNum );
  158. if ( !FStrEq( currentPlayerName, player ) )
  159. {
  160. char command[128];
  161. Q_snprintf( command, sizeof(command), "spec_player \"%s\"", player );
  162. engine->ClientCmd( command );
  163. }
  164. }
  165. }
  166. }
  167. void CSpectatorMenu::OnCommand( const char *command )
  168. {
  169. if (!stricmp(command, "specnext") )
  170. {
  171. engine->ClientCmd("spec_next");
  172. }
  173. else if (!stricmp(command, "specprev") )
  174. {
  175. engine->ClientCmd("spec_prev");
  176. }
  177. }
  178. void CSpectatorMenu::FireGameEvent( IGameEvent * event )
  179. {
  180. const char *pEventName = event->GetName();
  181. if ( Q_strcmp( "spec_target_updated", pEventName ) == 0 )
  182. {
  183. IGameResources *gr = GameResources();
  184. if ( !gr )
  185. return;
  186. // make sure the player combo box is up to date
  187. int playernum = GetSpectatorTarget();
  188. if ( playernum < 1 || playernum > MAX_PLAYERS )
  189. return;
  190. const char *selectedPlayerName = gr->GetPlayerName( playernum );
  191. const char *currentPlayerName = "";
  192. KeyValues *kv = m_pPlayerList->GetActiveItemUserData();
  193. if ( kv )
  194. {
  195. currentPlayerName = kv->GetString( "player" );
  196. }
  197. if ( !FStrEq( currentPlayerName, selectedPlayerName ) )
  198. {
  199. for ( int i=0; i<m_pPlayerList->GetItemCount(); ++i )
  200. {
  201. KeyValues *kv = m_pPlayerList->GetItemUserData( i );
  202. if ( kv && FStrEq( kv->GetString( "player" ), selectedPlayerName ) )
  203. {
  204. m_pPlayerList->ActivateItemByRow( i );
  205. break;
  206. }
  207. }
  208. }
  209. }
  210. }
  211. //-----------------------------------------------------------------------------
  212. // Purpose: when duck is pressed it hides the active part of the GUI
  213. //-----------------------------------------------------------------------------
  214. void CSpectatorMenu::OnKeyCodePressed(KeyCode code)
  215. {
  216. if ( code == m_iDuckKey )
  217. {
  218. // hide if DUCK is pressed again
  219. m_pViewPort->ShowPanel( this, false );
  220. }
  221. }
  222. void CSpectatorMenu::ShowPanel(bool bShow)
  223. {
  224. if ( BaseClass::IsVisible() == bShow )
  225. return;
  226. if ( bShow )
  227. {
  228. Activate();
  229. SetMouseInputEnabled( true );
  230. SetKeyBoardInputEnabled( true );
  231. }
  232. else
  233. {
  234. SetVisible( false );
  235. SetMouseInputEnabled( false );
  236. SetKeyBoardInputEnabled( false );
  237. }
  238. bool bIsEnabled = true;
  239. #if defined( REPLAY_ENABLED )
  240. if ( (g_bEngineIsHLTV && HLTVCamera()->IsPVSLocked()) ||
  241. (engine->IsReplay() && ReplayCamera()->IsPVSLocked()) )
  242. #else
  243. if ( g_bEngineIsHLTV && HLTVCamera()->IsPVSLocked() )
  244. #endif
  245. {
  246. // when watching HLTV or Replay with a locked PVS, some elements are disabled
  247. bIsEnabled = false;
  248. }
  249. m_pLeftButton->SetVisible( bIsEnabled );
  250. m_pRightButton->SetVisible( bIsEnabled );
  251. m_pPlayerList->SetVisible( bIsEnabled );
  252. m_pViewOptions->SetVisible( bIsEnabled );
  253. }
  254. void CSpectatorMenu::Update( void )
  255. {
  256. IGameResources *gr = GameResources();
  257. Reset();
  258. if ( m_iDuckKey == BUTTON_CODE_INVALID )
  259. {
  260. m_iDuckKey = gameuifuncs->GetButtonCodeForBind( "duck" );
  261. }
  262. if ( !gr )
  263. return;
  264. int iPlayerIndex;
  265. for ( iPlayerIndex = 1 ; iPlayerIndex <= gpGlobals->maxClients; iPlayerIndex++ )
  266. {
  267. // does this slot in the array have a name?
  268. if ( !gr->IsConnected( iPlayerIndex ) )
  269. continue;
  270. if ( gr->IsLocalPlayer( iPlayerIndex ) )
  271. continue;
  272. if ( !gr->IsAlive( iPlayerIndex ) )
  273. continue;
  274. wchar_t playerText[ 80 ], playerName[ 64 ], *team, teamText[ 64 ];
  275. char localizeTeamName[64];
  276. char szPlayerIndex[16];
  277. g_pVGuiLocalize->ConvertANSIToUnicode( UTIL_SafeName( gr->GetPlayerName(iPlayerIndex) ), playerName, sizeof( playerName ) );
  278. const char * teamname = gr->GetTeamName( gr->GetTeam(iPlayerIndex) );
  279. if ( teamname )
  280. {
  281. Q_snprintf( localizeTeamName, sizeof( localizeTeamName ), "#%s", teamname );
  282. team=g_pVGuiLocalize->Find( localizeTeamName );
  283. if ( !team )
  284. {
  285. g_pVGuiLocalize->ConvertANSIToUnicode( teamname , teamText, sizeof( teamText ) );
  286. team = teamText;
  287. }
  288. g_pVGuiLocalize->ConstructString( playerText, sizeof( playerText ), g_pVGuiLocalize->Find( "#Spec_PlayerItem_Team" ), 2, playerName, team );
  289. }
  290. else
  291. {
  292. g_pVGuiLocalize->ConstructString( playerText, sizeof( playerText ), g_pVGuiLocalize->Find( "#Spec_PlayerItem" ), 1, playerName );
  293. }
  294. Q_snprintf( szPlayerIndex, sizeof( szPlayerIndex ), "%d", iPlayerIndex );
  295. KeyValues *kv = new KeyValues( "UserData", "player", gr->GetPlayerName( iPlayerIndex ), "index", szPlayerIndex );
  296. m_pPlayerList->AddItem( playerText, kv );
  297. kv->deleteThis();
  298. }
  299. // make sure the player combo box is up to date
  300. int playernum = GetSpectatorTarget();
  301. const char *selectedPlayerName = gr->GetPlayerName( playernum );
  302. for ( iPlayerIndex=0; iPlayerIndex<m_pPlayerList->GetItemCount(); ++iPlayerIndex )
  303. {
  304. KeyValues *kv = m_pPlayerList->GetItemUserData( iPlayerIndex );
  305. if ( kv && FStrEq( kv->GetString( "player" ), selectedPlayerName ) )
  306. {
  307. m_pPlayerList->ActivateItemByRow( iPlayerIndex );
  308. break;
  309. }
  310. }
  311. // make sure the view mode combo box is up to date - the spectator
  312. // mode can be changed multiple ways
  313. int specmode = GetSpectatorMode();
  314. m_pViewOptions->SetText(s_SpectatorModes[specmode]);
  315. }
  316. //-----------------------------------------------------------------------------
  317. // main spectator panel
  318. //-----------------------------------------------------------------------------
  319. // Purpose: Constructor
  320. //-----------------------------------------------------------------------------
  321. CSpectatorGUI::CSpectatorGUI(IViewPort *pViewPort) : EditablePanel( NULL, PANEL_SPECGUI )
  322. {
  323. // m_bHelpShown = false;
  324. // m_bInsetVisible = false;
  325. // m_iDuckKey = KEY_NONE;
  326. SetSize( 10, 10 ); // Quiet "parent not sized yet" spew
  327. m_bSpecScoreboard = false;
  328. m_pViewPort = pViewPort;
  329. g_pSpectatorGUI = this;
  330. // initialize dialog
  331. SetVisible(false);
  332. SetProportional(true);
  333. // load the new scheme early!!
  334. SetScheme("ClientScheme");
  335. SetMouseInputEnabled( false );
  336. SetKeyBoardInputEnabled( false );
  337. m_pTopBar = new Panel( this, "topbar" );
  338. m_pBottomBarBlank = new Panel( this, "bottombarblank" );
  339. // m_pBannerImage = new ImagePanel( m_pTopBar, NULL );
  340. m_pPlayerLabel = new Label( this, "playerlabel", "" );
  341. m_pPlayerLabel->SetVisible( false );
  342. TextImage *image = m_pPlayerLabel->GetTextImage();
  343. if ( image )
  344. {
  345. HFont hFallbackFont = scheme()->GetIScheme( GetScheme() )->GetFont( "DefaultVerySmallFallBack", false );
  346. if ( INVALID_FONT != hFallbackFont )
  347. {
  348. image->SetUseFallbackFont( true, hFallbackFont );
  349. }
  350. }
  351. SetPaintBorderEnabled(false);
  352. SetPaintBackgroundEnabled(false);
  353. // m_pBannerImage->SetVisible(false);
  354. InvalidateLayout();
  355. }
  356. //-----------------------------------------------------------------------------
  357. // Purpose: Destructor
  358. //-----------------------------------------------------------------------------
  359. CSpectatorGUI::~CSpectatorGUI()
  360. {
  361. g_pSpectatorGUI = NULL;
  362. }
  363. //-----------------------------------------------------------------------------
  364. // Purpose: Sets the colour of the top and bottom bars
  365. //-----------------------------------------------------------------------------
  366. void CSpectatorGUI::ApplySchemeSettings(IScheme *pScheme)
  367. {
  368. LoadControlSettings( GetResFile() );
  369. m_pBottomBarBlank->SetVisible( true );
  370. m_pTopBar->SetVisible( true );
  371. BaseClass::ApplySchemeSettings( pScheme );
  372. SetBgColor(Color( 0,0,0,0 ) ); // make the background transparent
  373. m_pTopBar->SetBgColor(GetBlackBarColor());
  374. m_pBottomBarBlank->SetBgColor(GetBlackBarColor());
  375. // m_pBottomBar->SetBgColor(Color( 0,0,0,0 ));
  376. SetPaintBorderEnabled(false);
  377. SetBorder( NULL );
  378. #ifdef CSTRIKE_DLL
  379. SetZPos(80); // guarantee it shows above the scope
  380. #endif
  381. }
  382. //-----------------------------------------------------------------------------
  383. // Purpose: makes the GUI fill the screen
  384. //-----------------------------------------------------------------------------
  385. void CSpectatorGUI::PerformLayout()
  386. {
  387. int w,h,x,y;
  388. GetHudSize(w, h);
  389. //offset for title safe viewing zone
  390. int safeX = 0;
  391. int safeY = (int)floorf( ScreenHeight() * 0.075f );
  392. SetBounds( safeX, safeY, w, h - ( safeY * 2 ) );
  393. m_pBottomBarBlank->GetPos( x, y );
  394. m_pBottomBarBlank->SetSize( w, h - y );
  395. }
  396. //-----------------------------------------------------------------------------
  397. // Purpose: checks spec_scoreboard cvar to see if the scoreboard should be displayed
  398. //-----------------------------------------------------------------------------
  399. void CSpectatorGUI::OnThink()
  400. {
  401. BaseClass::OnThink();
  402. if ( IsVisible() )
  403. {
  404. if ( m_bSpecScoreboard != spec_scoreboard.GetBool() )
  405. {
  406. if ( !spec_scoreboard.GetBool() || !GetViewPortInterface()->GetActivePanel() )
  407. {
  408. m_bSpecScoreboard = spec_scoreboard.GetBool();
  409. GetViewPortInterface()->ShowPanel( PANEL_SCOREBOARD, m_bSpecScoreboard );
  410. }
  411. }
  412. }
  413. }
  414. //-----------------------------------------------------------------------------
  415. // Purpose: sets the image to display for the banner in the top right corner
  416. //-----------------------------------------------------------------------------
  417. void CSpectatorGUI::SetLogoImage(const char *image)
  418. {
  419. if ( m_pBannerImage )
  420. {
  421. m_pBannerImage->SetImage( scheme()->GetImage(image, false) );
  422. }
  423. }
  424. //-----------------------------------------------------------------------------
  425. // Purpose: Sets the text of a control by name
  426. //-----------------------------------------------------------------------------
  427. void CSpectatorGUI::SetLabelText(const char *textEntryName, const char *text)
  428. {
  429. Label *entry = dynamic_cast<Label *>(FindChildByName(textEntryName));
  430. if (entry)
  431. {
  432. entry->SetText(text);
  433. }
  434. }
  435. //-----------------------------------------------------------------------------
  436. // Purpose: Sets the text of a control by name
  437. //-----------------------------------------------------------------------------
  438. void CSpectatorGUI::SetLabelText(const char *textEntryName, wchar_t *text)
  439. {
  440. Label *entry = dynamic_cast<Label *>(FindChildByName(textEntryName));
  441. if (entry)
  442. {
  443. entry->SetText(text);
  444. }
  445. }
  446. //-----------------------------------------------------------------------------
  447. // Purpose: Sets the text of a control by name
  448. //-----------------------------------------------------------------------------
  449. void CSpectatorGUI::MoveLabelToFront(const char *textEntryName)
  450. {
  451. Label *entry = dynamic_cast<Label *>(FindChildByName(textEntryName));
  452. if (entry)
  453. {
  454. entry->MoveToFront();
  455. }
  456. }
  457. //-----------------------------------------------------------------------------
  458. // Purpose: shows/hides the buy menu
  459. //-----------------------------------------------------------------------------
  460. void CSpectatorGUI::ShowPanel(bool bShow)
  461. {
  462. if ( bShow && !IsVisible() )
  463. {
  464. m_bSpecScoreboard = false;
  465. }
  466. SetVisible( bShow );
  467. if ( !bShow && m_bSpecScoreboard )
  468. {
  469. GetViewPortInterface()->ShowPanel( PANEL_SCOREBOARD, false );
  470. }
  471. }
  472. bool CSpectatorGUI::ShouldShowPlayerLabel( int specmode )
  473. {
  474. return ( (specmode == OBS_MODE_IN_EYE) || (specmode == OBS_MODE_CHASE) );
  475. }
  476. //-----------------------------------------------------------------------------
  477. // Purpose: Updates the gui, rearranges elements
  478. //-----------------------------------------------------------------------------
  479. void CSpectatorGUI::Update()
  480. {
  481. int wide, tall;
  482. int bx, by, bwide, btall;
  483. GetHudSize(wide, tall);
  484. m_pTopBar->GetBounds( bx, by, bwide, btall );
  485. IGameResources *gr = GameResources();
  486. int specmode = GetSpectatorMode();
  487. int playernum = GetSpectatorTarget();
  488. IViewPortPanel *overview = GetViewPortInterface()->FindPanelByName( PANEL_OVERVIEW );
  489. if ( overview && overview->IsVisible() )
  490. {
  491. int mx, my, mwide, mtall;
  492. VPANEL p = overview->GetVPanel();
  493. vgui::ipanel()->GetPos( p, mx, my );
  494. vgui::ipanel()->GetSize( p, mwide, mtall );
  495. if ( my < btall )
  496. {
  497. // reduce to bar
  498. m_pTopBar->SetSize( wide - (mx + mwide), btall );
  499. m_pTopBar->SetPos( (mx + mwide), 0 );
  500. }
  501. else
  502. {
  503. // full top bar
  504. m_pTopBar->SetSize( wide , btall );
  505. m_pTopBar->SetPos( 0, 0 );
  506. }
  507. }
  508. else
  509. {
  510. // full top bar
  511. m_pTopBar->SetSize( wide , btall ); // change width, keep height
  512. m_pTopBar->SetPos( 0, 0 );
  513. }
  514. m_pPlayerLabel->SetVisible( ShouldShowPlayerLabel(specmode) );
  515. // update player name filed, text & color
  516. if ( playernum > 0 && playernum <= gpGlobals->maxClients && gr )
  517. {
  518. Color c = gr->GetTeamColor( gr->GetTeam(playernum) ); // Player's team color
  519. m_pPlayerLabel->SetFgColor( c );
  520. wchar_t playerText[ 80 ], playerName[ 64 ], health[ 10 ];
  521. wcscpy( playerText, L"Unable to find #Spec_PlayerItem*" );
  522. memset( playerName, 0x0, sizeof( playerName ) );
  523. g_pVGuiLocalize->ConvertANSIToUnicode( UTIL_SafeName(gr->GetPlayerName( playernum )), playerName, sizeof( playerName ) );
  524. int iHealth = gr->GetHealth( playernum );
  525. if ( iHealth > 0 && gr->IsAlive(playernum) )
  526. {
  527. _snwprintf( health, ARRAYSIZE( health ), L"%i", iHealth );
  528. g_pVGuiLocalize->ConstructString( playerText, sizeof( playerText ), g_pVGuiLocalize->Find( "#Spec_PlayerItem_Team" ), 2, playerName, health );
  529. }
  530. else
  531. {
  532. g_pVGuiLocalize->ConstructString( playerText, sizeof( playerText ), g_pVGuiLocalize->Find( "#Spec_PlayerItem" ), 1, playerName );
  533. }
  534. m_pPlayerLabel->SetText( playerText );
  535. }
  536. else
  537. {
  538. m_pPlayerLabel->SetText( L"" );
  539. }
  540. // update extra info field
  541. wchar_t szEtxraInfo[1024];
  542. wchar_t szTitleLabel[1024];
  543. char tempstr[128];
  544. if ( g_bEngineIsHLTV )
  545. {
  546. // set spectator number and HLTV title
  547. Q_snprintf(tempstr,sizeof(tempstr),"Spectators : %d", HLTVCamera()->GetNumSpectators() );
  548. g_pVGuiLocalize->ConvertANSIToUnicode(tempstr,szEtxraInfo,sizeof(szEtxraInfo));
  549. Q_strncpy( tempstr, HLTVCamera()->GetTitleText(), sizeof(tempstr) );
  550. g_pVGuiLocalize->ConvertANSIToUnicode(tempstr,szTitleLabel,sizeof(szTitleLabel));
  551. }
  552. #if defined( REPLAY_ENABLED )
  553. else if ( engine->IsReplay() )
  554. {
  555. // set spectator number and Replay title
  556. Q_snprintf(tempstr,sizeof(tempstr),"Spectators : %d", ReplayCamera()->GetNumSpectators() );
  557. g_pVGuiLocalize->ConvertANSIToUnicode(tempstr,szEtxraInfo,sizeof(szEtxraInfo));
  558. Q_strncpy( tempstr, ReplayCamera()->GetTitleText(), sizeof(tempstr) );
  559. g_pVGuiLocalize->ConvertANSIToUnicode(tempstr,szTitleLabel,sizeof(szTitleLabel));
  560. }
  561. #endif
  562. else
  563. {
  564. // otherwise show map name
  565. Q_FileBase( engine->GetLevelName(), tempstr, sizeof(tempstr) );
  566. wchar_t wMapName[64];
  567. g_pVGuiLocalize->ConvertANSIToUnicode(tempstr,wMapName,sizeof(wMapName));
  568. g_pVGuiLocalize->ConstructString( szEtxraInfo,sizeof( szEtxraInfo ), g_pVGuiLocalize->Find("#Spec_Map" ),1, wMapName );
  569. g_pVGuiLocalize->ConvertANSIToUnicode( "" ,szTitleLabel,sizeof(szTitleLabel));
  570. }
  571. SetLabelText("extrainfo", szEtxraInfo );
  572. SetLabelText("titlelabel", szTitleLabel );
  573. }
  574. //-----------------------------------------------------------------------------
  575. // Purpose: Updates the timer label if one exists
  576. //-----------------------------------------------------------------------------
  577. void CSpectatorGUI::UpdateTimer()
  578. {
  579. wchar_t szText[ 64 ];
  580. int timer = 0;
  581. _snwprintf ( szText, ARRAYSIZE( szText ), L"%d:%02d\n", (timer / 60), (timer % 60) );
  582. szText[63] = 0;
  583. SetLabelText("timerlabel", szText );
  584. }
  585. static void ForwardSpecCmdToServer( const CCommand &args )
  586. {
  587. if ( engine->IsPlayingDemo() )
  588. return;
  589. if ( args.ArgC() == 1 )
  590. {
  591. // just forward the command without parameters
  592. engine->ServerCmd( args[ 0 ] );
  593. }
  594. else if ( args.ArgC() == 2 )
  595. {
  596. // forward the command with parameter
  597. char command[128];
  598. Q_snprintf( command, sizeof(command), "%s \"%s\"", args[ 0 ], args[ 1 ] );
  599. engine->ServerCmd( command );
  600. }
  601. }
  602. CON_COMMAND_F( spec_next, "Spectate next player", FCVAR_CLIENTCMD_CAN_EXECUTE )
  603. {
  604. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  605. if ( !pPlayer || !pPlayer->IsObserver() )
  606. return;
  607. if ( g_bEngineIsHLTV )
  608. {
  609. // handle the command clientside
  610. if ( !HLTVCamera()->IsPVSLocked() )
  611. {
  612. HLTVCamera()->SpecNextPlayer( false );
  613. }
  614. }
  615. #if defined( REPLAY_ENABLED )
  616. else if ( engine->IsReplay() )
  617. {
  618. // handle the command clientside
  619. if ( !ReplayCamera()->IsPVSLocked() )
  620. {
  621. ReplayCamera()->SpecNextPlayer( false );
  622. }
  623. }
  624. #endif
  625. else
  626. {
  627. ForwardSpecCmdToServer( args );
  628. }
  629. }
  630. CON_COMMAND_F( spec_prev, "Spectate previous player", FCVAR_CLIENTCMD_CAN_EXECUTE )
  631. {
  632. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  633. if ( !pPlayer || !pPlayer->IsObserver() )
  634. return;
  635. if ( g_bEngineIsHLTV )
  636. {
  637. // handle the command clientside
  638. if ( !HLTVCamera()->IsPVSLocked() )
  639. {
  640. HLTVCamera()->SpecNextPlayer( true );
  641. }
  642. }
  643. #if defined( REPLAY_ENABLED )
  644. else if ( engine->IsReplay() )
  645. {
  646. // handle the command clientside
  647. if ( !ReplayCamera()->IsPVSLocked() )
  648. {
  649. ReplayCamera()->SpecNextPlayer( true );
  650. }
  651. }
  652. #endif
  653. else
  654. {
  655. ForwardSpecCmdToServer( args );
  656. }
  657. }
  658. CON_COMMAND_F( spec_mode, "Set spectator mode", FCVAR_CLIENTCMD_CAN_EXECUTE )
  659. {
  660. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  661. if ( !pPlayer || !pPlayer->IsObserver() )
  662. return;
  663. if ( g_bEngineIsHLTV )
  664. {
  665. if ( HLTVCamera()->IsPVSLocked() )
  666. {
  667. // in locked mode we can only switch between first and 3rd person
  668. HLTVCamera()->ToggleChaseAsFirstPerson();
  669. }
  670. else
  671. {
  672. // we can choose any mode, not loked to PVS
  673. int mode;
  674. if ( args.ArgC() == 2 )
  675. {
  676. // set specifc mode
  677. mode = Q_atoi( args[1] );
  678. }
  679. else
  680. {
  681. // set next mode
  682. mode = HLTVCamera()->GetMode()+1;
  683. if ( mode > LAST_PLAYER_OBSERVERMODE )
  684. mode = OBS_MODE_IN_EYE;
  685. }
  686. // handle the command clientside
  687. HLTVCamera()->SetMode( mode );
  688. }
  689. // turn off auto director once user tried to change view settings
  690. HLTVCamera()->SetAutoDirector( false );
  691. }
  692. #if defined( REPLAY_ENABLED )
  693. else if ( engine->IsReplay() )
  694. {
  695. if ( ReplayCamera()->IsPVSLocked() )
  696. {
  697. // in locked mode we can only switch between first and 3rd person
  698. ReplayCamera()->ToggleChaseAsFirstPerson();
  699. }
  700. else
  701. {
  702. // we can choose any mode, not loked to PVS
  703. int mode;
  704. if ( args.ArgC() == 2 )
  705. {
  706. // set specifc mode
  707. mode = Q_atoi( args[1] );
  708. }
  709. else
  710. {
  711. // set next mode
  712. mode = ReplayCamera()->GetMode()+1;
  713. if ( mode > LAST_PLAYER_OBSERVERMODE )
  714. mode = OBS_MODE_IN_EYE;
  715. }
  716. // handle the command clientside
  717. ReplayCamera()->SetMode( mode );
  718. }
  719. // turn off auto director once user tried to change view settings
  720. ReplayCamera()->SetAutoDirector( false );
  721. }
  722. #endif
  723. else
  724. {
  725. // we spectate on a game server, forward command
  726. ForwardSpecCmdToServer( args );
  727. }
  728. }
  729. CON_COMMAND_F( spec_player, "Spectate player by name", FCVAR_CLIENTCMD_CAN_EXECUTE )
  730. {
  731. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  732. if ( !pPlayer || !pPlayer->IsObserver() )
  733. return;
  734. if ( args.ArgC() != 2 )
  735. return;
  736. if ( g_bEngineIsHLTV )
  737. {
  738. // we can only switch primary spectator targets is PVS isnt locked by auto-director
  739. if ( !HLTVCamera()->IsPVSLocked() )
  740. {
  741. HLTVCamera()->SpecNamedPlayer( args[1] );
  742. }
  743. }
  744. #if defined( REPLAY_ENABLED )
  745. else if ( engine->IsReplay() )
  746. {
  747. // we can only switch primary spectator targets is PVS isnt locked by auto-director
  748. if ( !ReplayCamera()->IsPVSLocked() )
  749. {
  750. ReplayCamera()->SpecNamedPlayer( args[1] );
  751. }
  752. }
  753. #endif
  754. else
  755. {
  756. ForwardSpecCmdToServer( args );
  757. }
  758. }