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.

1370 lines
39 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "tf_hud_freezepanel.h"
  9. #include "vgui_controls/AnimationController.h"
  10. #include "iclientmode.h"
  11. #include "c_tf_player.h"
  12. #include "c_tf_playerresource.h"
  13. #include <vgui_controls/Label.h>
  14. #include <vgui/ILocalize.h>
  15. #include <vgui/ISurface.h>
  16. #include <vgui/IInput.h>
  17. #include "c_baseobject.h"
  18. #include "fmtstr.h"
  19. #include "tf_gamerules.h"
  20. #include "tf_hud_statpanel.h"
  21. #include "view.h"
  22. #include "ivieweffects.h"
  23. #include "viewrender.h"
  24. #include "c_obj_sentrygun.h"
  25. #include "NextBot/C_NextBot.h"
  26. #include "halloween/c_headless_hatman.h"
  27. #include "halloween/c_eyeball_boss.h"
  28. #include "halloween/c_merasmus.h"
  29. #include "tf_wardata.h"
  30. #if defined( REPLAY_ENABLED )
  31. #include "replay/ireplaysystem.h"
  32. #include "replay/ireplaymanager.h"
  33. #include "replay/replay.h"
  34. #include "replay/screenshot.h"
  35. #include "replay/ireplayscreenshotmanager.h"
  36. #include "replay/vgui/replayreminderpanel.h"
  37. #endif
  38. // memdbgon must be the last include file in a .cpp file!!!
  39. #include "tier0/memdbgon.h"
  40. DECLARE_HUDELEMENT_DEPTH( CTFFreezePanel, 1 );
  41. #define CALLOUT_WIDE (XRES(100))
  42. #define CALLOUT_TALL (XRES(50))
  43. extern float g_flFreezeFlash;
  44. #define FREEZECAM_SCREENSHOT_STRING "is looking good!"
  45. extern ConVar hud_freezecamhide;
  46. bool IsTakingAFreezecamScreenshot( void )
  47. {
  48. // Don't draw in freezecam, or when the game's not running
  49. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  50. bool bInFreezeCam = ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM );
  51. if ( bInFreezeCam == true && engine->IsTakingScreenshot() )
  52. return true;
  53. CTFFreezePanel *pFreezePanel = CTFFreezePanel::Instance();
  54. if ( pFreezePanel )
  55. {
  56. if ( pFreezePanel->IsHoldingAfterScreenShot() )
  57. return true;
  58. }
  59. return false;
  60. }
  61. DECLARE_BUILD_FACTORY( CTFFreezePanelHealth );
  62. //-----------------------------------------------------------------------------
  63. CTFFreezePanel *CTFFreezePanel::s_pFreezePanel = NULL;
  64. //-----------------------------------------------------------------------------
  65. CTFFreezePanel *CTFFreezePanel::Instance()
  66. {
  67. return s_pFreezePanel;
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Purpose: Constructor
  71. //-----------------------------------------------------------------------------
  72. CTFFreezePanel::CTFFreezePanel( const char *pElementName )
  73. : EditablePanel( NULL, "FreezePanel" ), CHudElement( pElementName )
  74. {
  75. AssertMsg( !s_pFreezePanel, "There can be only one." );
  76. s_pFreezePanel = this;
  77. vgui::Panel *pParent = g_pClientMode->GetViewport();
  78. SetParent( pParent );
  79. SetVisible( false );
  80. SetScheme( "ClientScheme" );
  81. m_iKillerIndex = 0;
  82. m_iShowNemesisPanel = SHOW_NO_NEMESIS;
  83. m_iYBase = -1;
  84. m_flShowCalloutsAt = 0;
  85. m_iBasePanelOriginalX = -1;
  86. m_iBasePanelOriginalY = -1;
  87. m_pItemPanel = new CItemModelPanel( this, "itempanel" ) ;
  88. m_iItemPanelOriginalX = -1;
  89. m_iItemPanelOriginalY = -1;
  90. #if defined( REPLAY_ENABLED )
  91. m_pSaveReplayPanel = GET_HUDELEMENT( CReplayReminderPanel ); // Use the HUD's instance
  92. #endif
  93. m_strCurrentFreezeCamResFile = GetResFilename();
  94. }
  95. //-----------------------------------------------------------------------------
  96. // Purpose:
  97. //-----------------------------------------------------------------------------
  98. void CTFFreezePanel::Reset()
  99. {
  100. Hide();
  101. if ( m_pKillerHealth )
  102. {
  103. m_pKillerHealth->Reset();
  104. }
  105. }
  106. //-----------------------------------------------------------------------------
  107. // Purpose:
  108. //-----------------------------------------------------------------------------
  109. void CTFFreezePanel::Init()
  110. {
  111. // listen for events
  112. ListenForGameEvent( "show_freezepanel" );
  113. ListenForGameEvent( "hide_freezepanel" );
  114. ListenForGameEvent( "freezecam_started" );
  115. ListenForGameEvent( "player_death" );
  116. ListenForGameEvent( "teamplay_win_panel" );
  117. ListenForGameEvent( "training_complete" );
  118. Hide();
  119. CHudElement::Init();
  120. }
  121. //-----------------------------------------------------------------------------
  122. // Purpose:
  123. //-----------------------------------------------------------------------------
  124. void CTFFreezePanel::SendTauntAcknowledgement( const char *pszCommand, int iGibs )
  125. {
  126. C_TFPlayer *pKiller = ToTFPlayer( UTIL_PlayerByIndex( GetSpectatorTarget() ) );
  127. if ( pKiller && pKiller->m_Shared.InCond( TF_COND_TAUNTING ) )
  128. {
  129. CTFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
  130. if ( pPlayer )
  131. {
  132. KeyValues *kv = new KeyValues( "FreezeCamTaunt" );
  133. kv->SetInt( "achiever", pKiller->GetUserID() );
  134. kv->SetString( "command", pszCommand );
  135. kv->SetInt( "gibs", iGibs );
  136. engine->ServerCmdKeyValues( kv );
  137. }
  138. }
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Purpose: Applies scheme settings
  142. //-----------------------------------------------------------------------------
  143. void CTFFreezePanel::ApplySchemeSettings( vgui::IScheme *pScheme )
  144. {
  145. BaseClass::ApplySchemeSettings( pScheme );
  146. Assert( !m_strCurrentFreezeCamResFile.IsEmpty() );
  147. LoadControlSettings( m_strCurrentFreezeCamResFile.String() );
  148. m_pBasePanel = dynamic_cast<EditablePanel *>( FindChildByName("FreezePanelBase") );
  149. Assert( m_pBasePanel );
  150. if ( m_pBasePanel )
  151. {
  152. m_pFreezeLabel = dynamic_cast<Label *>( m_pBasePanel->FindChildByName("FreezeLabel") );
  153. m_pKillerLabel = dynamic_cast<Label *>( m_pBasePanel->FindChildByName("FreezeLabelKiller") );
  154. m_pFreezePanelBG = dynamic_cast<CTFImagePanel *>( m_pBasePanel->FindChildByName( "FreezePanelBG" ) );
  155. m_pNemesisSubPanel = dynamic_cast<EditablePanel *>( m_pBasePanel->FindChildByName( "NemesisSubPanel" ) );
  156. m_pKillerHealth = dynamic_cast<CTFFreezePanelHealth *>( m_pBasePanel->FindChildByName( "FreezePanelHealth" ) );
  157. m_pAvatar = dynamic_cast<CAvatarImagePanel *>( m_pBasePanel->FindChildByName("AvatarImage") );
  158. m_pFreezeTeamIcon = dynamic_cast<CTFImagePanel *>( m_pBasePanel->FindChildByName( "FreezeTeamIcon" ) );
  159. if ( m_pAvatar )
  160. {
  161. m_pAvatar->SetShouldScaleImage( true );
  162. m_pAvatar->SetShouldDrawFriendIcon( false );
  163. }
  164. }
  165. m_pScreenshotPanel = dynamic_cast<EditablePanel *>( FindChildByName( "ScreenshotPanel" ) );
  166. Assert( m_pScreenshotPanel );
  167. // Move killer panels when the win panel is up
  168. int xp,yp;
  169. GetPos( xp, yp );
  170. m_iYBase = yp;
  171. int w = 0 , h = 0;
  172. if ( m_pBasePanel )
  173. m_pBasePanel->GetBounds( m_iBasePanelOriginalX, m_iBasePanelOriginalY, w, h );
  174. m_pItemPanel->GetBounds( m_iItemPanelOriginalX, m_iItemPanelOriginalY, w, h );
  175. if ( m_pKillerLabel )
  176. {
  177. m_pKillerLabel->GetPos( m_iKillerOriginalX, m_iKillerOriginalY );
  178. }
  179. }
  180. //-----------------------------------------------------------------------------
  181. // Purpose:
  182. //-----------------------------------------------------------------------------
  183. void CTFFreezePanel::FireGameEvent( IGameEvent * event )
  184. {
  185. const char *pEventName = event->GetName();
  186. if ( Q_strcmp( "player_death", pEventName ) == 0 )
  187. {
  188. // see if the local player died
  189. int iPlayerIndexVictim = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
  190. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  191. if ( pLocalPlayer && iPlayerIndexVictim == pLocalPlayer->entindex() )
  192. {
  193. // the local player is dead, see if this is a new nemesis or a revenge
  194. if (event->GetInt( "death_flags" ) & TF_DEATH_DOMINATION )
  195. {
  196. m_iShowNemesisPanel = SHOW_NEW_NEMESIS;
  197. }
  198. else if ( event->GetInt( "death_flags" ) & TF_DEATH_REVENGE )
  199. {
  200. m_iShowNemesisPanel = SHOW_REVENGE;
  201. }
  202. else
  203. {
  204. m_iShowNemesisPanel = SHOW_NO_NEMESIS;
  205. }
  206. }
  207. }
  208. else if ( Q_strcmp( "hide_freezepanel", pEventName ) == 0 )
  209. {
  210. Hide();
  211. }
  212. else if ( Q_strcmp( "freezecam_started", pEventName ) == 0 )
  213. {
  214. ShowCalloutsIn( 1.0 );
  215. ShowSnapshotPanelIn( 1.25 );
  216. #if defined( REPLAY_ENABLED )
  217. // If Replay is enabled on the server, show the replay download reminder. If GetPendingReplay()
  218. // returns NULL, we know we've already saved the replay.
  219. CReplay *pCurLifeReplay = ( g_pReplayManager ) ? g_pReplayManager->GetReplayForCurrentLife() : NULL;
  220. if ( g_pReplay->IsRecording() && ( pCurLifeReplay && !pCurLifeReplay->m_bRequestedByUser && !pCurLifeReplay->m_bSaved ) )
  221. {
  222. ShowSaveReplayPanelIn( 1.25 );
  223. }
  224. // Save the freezeframe for the replay browser
  225. if ( g_pReplay->IsRecording() )
  226. {
  227. // Capture the freezecam in half a second
  228. CaptureScreenshotParams_t params;
  229. V_memset( &params, 0, sizeof( params ) );
  230. params.m_flDelay = 0.0f;
  231. params.m_bIgnoreMinTimeBetweenScreenshots = true;
  232. g_pReplayScreenshotManager->CaptureScreenshot( params );
  233. }
  234. #endif
  235. CTFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
  236. if ( pPlayer )
  237. {
  238. SendTauntAcknowledgement( "freezecam_taunt" );
  239. }
  240. }
  241. else if ( Q_strcmp( "teamplay_win_panel", pEventName ) == 0 )
  242. {
  243. Hide();
  244. }
  245. else if ( Q_strcmp( "training_complete", pEventName ) == 0 )
  246. {
  247. Hide();
  248. }
  249. else if ( Q_strcmp( "show_freezepanel", pEventName ) == 0 )
  250. {
  251. // Get the entity who killed us
  252. m_iKillerIndex = event->GetInt( "killer" );
  253. C_BaseEntity *pKiller = ClientEntityList().GetBaseEntity( m_iKillerIndex );
  254. CTFPlayer *pTFPlayerKiller = NULL;
  255. if ( pKiller )
  256. {
  257. if ( pKiller->IsPlayer() )
  258. {
  259. pTFPlayerKiller = ToTFPlayer( pKiller );
  260. }
  261. else if ( pKiller->IsBaseObject() )
  262. {
  263. C_BaseObject *pObj = assert_cast<C_BaseObject *>( pKiller );
  264. pTFPlayerKiller = pObj->GetOwner();
  265. }
  266. }
  267. // Do we need to invalidate a new res file?
  268. const char *pszNewResFile = GetResFilename( pTFPlayerKiller );
  269. if ( V_stricmp( m_strCurrentFreezeCamResFile.String(), pszNewResFile ) != 0 )
  270. {
  271. m_strCurrentFreezeCamResFile = pszNewResFile;
  272. InvalidateLayout( true, true );
  273. }
  274. if ( !g_TF_PR )
  275. {
  276. if ( m_pNemesisSubPanel )
  277. m_pNemesisSubPanel->SetDialogVariable( "nemesisname", NULL );
  278. return;
  279. }
  280. Show();
  281. ShowSnapshotPanel( false );
  282. ShowSaveReplayPanel( false );
  283. m_bHoldingAfterScreenshot = false;
  284. if ( m_iBasePanelOriginalX > -1 && m_iBasePanelOriginalY > -1 )
  285. {
  286. m_pBasePanel->SetPos( m_iBasePanelOriginalX, m_iBasePanelOriginalY );
  287. }
  288. if ( m_iItemPanelOriginalX > -1 && m_iItemPanelOriginalY > -1 )
  289. {
  290. m_pItemPanel->SetPos( m_iItemPanelOriginalX, m_iItemPanelOriginalY );
  291. }
  292. int xp,yp;
  293. GetPos( xp, yp );
  294. if ( TFGameRules()->RoundHasBeenWon() )
  295. {
  296. SetPos( xp, m_iYBase - YRES(50) );
  297. }
  298. else
  299. {
  300. SetPos( xp, m_iYBase );
  301. }
  302. if ( pKiller )
  303. {
  304. int iMaxBuffedHealth = 0;
  305. if ( pTFPlayerKiller )
  306. {
  307. iMaxBuffedHealth = pTFPlayerKiller->m_Shared.GetMaxBuffedHealth();
  308. }
  309. int iKillerHealth = pKiller->GetHealth();
  310. if ( !pKiller->IsAlive() )
  311. {
  312. iKillerHealth = 0;
  313. }
  314. m_pKillerHealth->SetBuilding( pKiller->IsBaseObject() );
  315. m_pKillerHealth->SetHealth( iKillerHealth, pKiller->GetMaxHealth(), iMaxBuffedHealth );
  316. if ( m_pItemPanel )
  317. {
  318. m_pItemPanel->SetVisible( false );
  319. }
  320. if ( pKiller->IsPlayer() )
  321. {
  322. C_TFPlayer *pVictim = C_TFPlayer::GetLocalTFPlayer();
  323. //If this was just a regular kill but this guy is our nemesis then just show it.
  324. if ( pVictim && pTFPlayerKiller->m_Shared.IsPlayerDominated( pVictim->entindex() ) )
  325. {
  326. if ( !pKiller->IsAlive() )
  327. {
  328. m_pFreezeLabel->SetText( "#FreezePanel_Nemesis_Dead" );
  329. }
  330. else
  331. {
  332. m_pFreezeLabel->SetText( "#FreezePanel_Nemesis" );
  333. }
  334. }
  335. else
  336. {
  337. if ( !pKiller->IsAlive() )
  338. {
  339. m_pFreezeLabel->SetText( "#FreezePanel_Killer_Dead" );
  340. }
  341. else
  342. {
  343. m_pFreezeLabel->SetText( "#FreezePanel_Killer" );
  344. }
  345. }
  346. m_pBasePanel->SetDialogVariable( "killername", g_PR->GetPlayerName( m_iKillerIndex ) );
  347. if ( m_pAvatar )
  348. {
  349. m_pAvatar->SetPlayer( (C_BasePlayer*)pKiller );
  350. }
  351. // If our killer is using a powerup, show the details of that powerup
  352. if ( pTFPlayerKiller && pTFPlayerKiller->m_Shared.IsCarryingRune() )
  353. {
  354. static CSchemaItemDefHandle rgPowerupItems [] = { CSchemaItemDefHandle( "Powerup Strength" )
  355. , CSchemaItemDefHandle( "Powerup Haste" )
  356. , CSchemaItemDefHandle( "Powerup Regen" )
  357. , CSchemaItemDefHandle( "Powerup Resist" )
  358. , CSchemaItemDefHandle( "Powerup Vampire" )
  359. , CSchemaItemDefHandle( "Powerup Reflect" )
  360. , CSchemaItemDefHandle( "Powerup Precision" )
  361. , CSchemaItemDefHandle( "Powerup Agility" )
  362. , CSchemaItemDefHandle( "Powerup Knockout" )
  363. , CSchemaItemDefHandle( "Powerup King" )
  364. , CSchemaItemDefHandle( "Powerup Plague" )
  365. , CSchemaItemDefHandle( "Powerup Supernova" ) };
  366. COMPILE_TIME_ASSERT( ARRAYSIZE( rgPowerupItems ) == RUNE_TYPES_MAX );
  367. // Get the item
  368. const CSchemaItemDefHandle& itemDef = rgPowerupItems[pTFPlayerKiller->m_Shared.GetCarryingRuneType()];
  369. // Create a fake, temp item to show the powerup
  370. CEconItemView item;
  371. item.SetItemDefIndex( itemDef->GetDefinitionIndex() );
  372. item.SetItemQuality( AE_UNIQUE ); // Unique by default
  373. item.SetItemLevel( 0 ); // Hide this?
  374. item.SetInitialized( true );
  375. item.SetItemOriginOverride( kEconItemOrigin_Invalid );
  376. m_pItemPanel->SetDialogVariable( "killername", g_PR->GetPlayerName( m_iKillerIndex ) );
  377. m_pItemPanel->SetItem( &item );
  378. m_pItemPanel->SetVisible( true );
  379. }
  380. else
  381. {
  382. // If our killer is using an item, display its stats.
  383. CTFWeaponBase *pWeapon = pTFPlayerKiller ? pTFPlayerKiller->GetActiveTFWeapon() : NULL;
  384. bool bShowItem = false;
  385. if ( pWeapon )
  386. {
  387. bShowItem = pWeapon->GetAttributeContainer()->GetItem()->GetItemQuality() != AE_NORMAL;
  388. if ( bShowItem )
  389. {
  390. CTFStatPanel *pStatPanel = GET_HUDELEMENT( CTFStatPanel );
  391. if ( pStatPanel && pStatPanel->IsVisible() )
  392. {
  393. // Stat panel overrides.
  394. bShowItem = false;
  395. }
  396. }
  397. }
  398. if ( bShowItem )
  399. {
  400. Label* pItemLabel = m_pItemPanel->FindControl<Label>( "ItemLabel" );
  401. if ( pItemLabel )
  402. {
  403. // Change the label text depending on if they're holding someone else's item
  404. CBasePlayer *pOriginalOwner = GetPlayerByAccountID( pWeapon->GetAttributeContainer()->GetItem()->GetAccountID() );
  405. bool bOriginalOwner = pOriginalOwner == pKiller;
  406. pItemLabel->SetText( bOriginalOwner ? "#FreezePanel_Item" : "#FreezePanel_ItemOtherOwner" );
  407. m_pItemPanel->SetDialogVariable( "ownername", bOriginalOwner ? g_PR->GetPlayerName( pOriginalOwner->entindex() ) : "" );
  408. }
  409. m_pItemPanel->SetDialogVariable( "killername", g_PR->GetPlayerName( m_iKillerIndex ) );
  410. m_pItemPanel->SetItem( pWeapon->GetAttributeContainer()->GetItem() );
  411. m_pItemPanel->SetVisible( true );
  412. }
  413. }
  414. if ( m_pItemPanel && m_pItemPanel->IsVisible() )
  415. {
  416. int x, y;
  417. m_pItemPanel->GetPos( x, y );
  418. m_pItemPanel->SetPos( x, ScreenHeight() - YRES( 12 ) - m_pItemPanel->GetTall() );
  419. }
  420. }
  421. else if ( pKiller->IsBaseObject() )
  422. {
  423. C_BaseObject *pObj = assert_cast<C_BaseObject *>( pKiller );
  424. //Assert( pTFPlayerKiller && "Why does this object not have an owner?" );
  425. if ( pTFPlayerKiller )
  426. {
  427. m_iKillerIndex = pTFPlayerKiller->entindex();
  428. m_pBasePanel->SetDialogVariable( "killername", g_PR->GetPlayerName( m_iKillerIndex ) );
  429. if ( m_pAvatar )
  430. {
  431. m_pAvatar->SetPlayer( pTFPlayerKiller );
  432. m_pAvatar->SetVisible( true );
  433. }
  434. pKiller = pTFPlayerKiller;
  435. }
  436. else
  437. {
  438. if ( m_pAvatar )
  439. {
  440. m_pAvatar->SetVisible( false );
  441. }
  442. }
  443. if ( m_pFreezeLabel )
  444. {
  445. if ( pKiller && !pKiller->IsAlive() )
  446. {
  447. m_pFreezeLabel->SetText( "#FreezePanel_KillerObject_Dead" );
  448. }
  449. else
  450. {
  451. m_pFreezeLabel->SetText( "#FreezePanel_KillerObject" );
  452. }
  453. }
  454. const char *pszStatusName = pObj->GetStatusName();
  455. wchar_t *wszLocalized = g_pVGuiLocalize->Find( pszStatusName );
  456. if ( !wszLocalized )
  457. {
  458. m_pBasePanel->SetDialogVariable( "objectkiller", pszStatusName );
  459. }
  460. else
  461. {
  462. m_pBasePanel->SetDialogVariable( "objectkiller", wszLocalized );
  463. }
  464. }
  465. else if ( dynamic_cast< C_HeadlessHatman * >( pKiller ) != NULL )
  466. {
  467. m_pBasePanel->SetDialogVariable( "killername", g_pVGuiLocalize->Find( "#TF_HALLOWEEN_BOSS_DEATHCAM_NAME" ) );
  468. if ( m_pAvatar )
  469. {
  470. m_pAvatar->SetVisible( false );
  471. }
  472. }
  473. else if ( dynamic_cast< C_EyeballBoss * >( pKiller ) != NULL )
  474. {
  475. m_pBasePanel->SetDialogVariable( "killername", g_pVGuiLocalize->Find( "#TF_HALLOWEEN_EYEBALL_BOSS_DEATHCAM_NAME" ) );
  476. if ( m_pAvatar )
  477. {
  478. m_pAvatar->SetVisible( false );
  479. }
  480. }
  481. else if ( dynamic_cast< C_Merasmus * >( pKiller ) != NULL )
  482. {
  483. m_pBasePanel->SetDialogVariable( "killername", g_pVGuiLocalize->Find( "#TF_HALLOWEEN_MERASMUS_DEATHCAM_NAME" ) );
  484. if ( m_pAvatar )
  485. {
  486. m_pAvatar->SetVisible( false );
  487. }
  488. }
  489. else if ( m_pFreezeLabel )
  490. {
  491. if ( !pKiller->IsAlive() )
  492. {
  493. m_pFreezeLabel->SetText( "#FreezePanel_Killer_Dead" );
  494. }
  495. else
  496. {
  497. m_pFreezeLabel->SetText( "#FreezePanel_Killer" );
  498. }
  499. }
  500. if ( m_pFreezePanelBG )
  501. {
  502. // use the killer's team for the background color
  503. m_pFreezePanelBG->SetImage( pKiller->GetTeamNumber() == TF_TEAM_BLUE ? "../hud/color_panel_blu" : "../hud/color_panel_red" );
  504. }
  505. if ( m_pAvatar )
  506. {
  507. int iAvX, iAvY;
  508. m_pAvatar->GetPos( iAvX, iAvY );
  509. if ( m_pAvatar->IsVisible() && m_pAvatar->IsValid() )
  510. {
  511. m_pKillerLabel->SetPos( iAvX + m_pAvatar->GetWide() + XRES(2), m_iKillerOriginalY );
  512. }
  513. else
  514. {
  515. m_pKillerLabel->SetPos( iAvX, m_iKillerOriginalY );
  516. }
  517. }
  518. }
  519. // see if we should show nemesis panel
  520. bool bAdvice = false;
  521. const wchar_t *pchNemesisText = NULL;
  522. switch ( m_iShowNemesisPanel )
  523. {
  524. case SHOW_NO_NEMESIS:
  525. {
  526. C_TFPlayer *pVictim = C_TFPlayer::GetLocalTFPlayer();
  527. CTFPlayer *pTFKiller = ToTFPlayer( pKiller );
  528. //If this was just a regular kill but this guy is our nemesis then just show it.
  529. if ( pTFKiller && pTFKiller->m_Shared.IsPlayerDominated( pVictim->entindex() ) )
  530. {
  531. pchNemesisText = g_pVGuiLocalize->Find( "#TF_FreezeNemesis" );
  532. }
  533. // UNDONE: We're not shipping this for now
  534. /*else if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() && pTFKiller && pTFKiller->GetTeamNumber() == TF_TEAM_PVE_INVADERS )
  535. {
  536. const wchar_t *pwchHint = g_pVGuiLocalize->Find( VarArgs( "#TF_PVE_FreezePanelHint_%s", pTFKiller->GetPlayerClass()->GetClassIconName() ) );
  537. if ( pwchHint && pwchHint[ 0 ] != L'\0' )
  538. {
  539. pchNemesisText = pwchHint;
  540. bAdvice = true;
  541. }
  542. }*/
  543. }
  544. break;
  545. case SHOW_NEW_NEMESIS:
  546. {
  547. C_TFPlayer *pVictim = C_TFPlayer::GetLocalTFPlayer();
  548. CTFPlayer *pTFKiller = ToTFPlayer( pKiller );
  549. // check to see if killer is still the nemesis of victim; victim may have managed to kill him after victim's
  550. // death by grenade or some such, extracting revenge and clearing nemesis condition
  551. if ( pTFKiller && pTFKiller->m_Shared.IsPlayerDominated( pVictim->entindex() ) )
  552. {
  553. pchNemesisText = g_pVGuiLocalize->Find( "#TF_NewNemesis" );
  554. }
  555. }
  556. break;
  557. case SHOW_REVENGE:
  558. pchNemesisText = g_pVGuiLocalize->Find( "#TF_GotRevenge" );
  559. break;
  560. default:
  561. Assert( false ); // invalid value
  562. break;
  563. }
  564. if ( m_pNemesisSubPanel )
  565. {
  566. if ( !bAdvice )
  567. {
  568. m_pNemesisSubPanel->SetDialogVariable( "nemesisname", pchNemesisText );
  569. m_pNemesisSubPanel->SetControlVisible( "NemesisLabel2", false );
  570. }
  571. else
  572. {
  573. m_pNemesisSubPanel->SetDialogVariable( "nemesisname", "" );
  574. m_pNemesisSubPanel->SetControlVisible( "NemesisLabel2", true );
  575. m_pNemesisSubPanel->SetDialogVariable( "nemesisadvice", pchNemesisText );
  576. }
  577. }
  578. ShowNemesisPanel( pchNemesisText != NULL );
  579. m_iShowNemesisPanel = SHOW_NO_NEMESIS;
  580. }
  581. }
  582. //-----------------------------------------------------------------------------
  583. // Purpose:
  584. //-----------------------------------------------------------------------------
  585. const char *CTFFreezePanel::GetResFilename( C_TFPlayer *pTFPlayer /*= NULL*/ ) const
  586. {
  587. return "resource/UI/FreezePanel_Basic.res";
  588. }
  589. //-----------------------------------------------------------------------------
  590. // Purpose:
  591. //-----------------------------------------------------------------------------
  592. void CTFFreezePanel::ShowCalloutsIn( float flTime )
  593. {
  594. m_flShowCalloutsAt = gpGlobals->curtime + flTime;
  595. }
  596. //-----------------------------------------------------------------------------
  597. // Purpose:
  598. //-----------------------------------------------------------------------------
  599. CTFFreezePanelCallout *CTFFreezePanel::TestAndAddCallout( Vector &origin, Vector &vMins, Vector &vMaxs, CUtlVector<Vector> *vecCalloutsTL,
  600. CUtlVector<Vector> *vecCalloutsBR, Vector &vecFreezeTL, Vector &vecFreezeBR, Vector &vecStatTL, Vector &vecStatBR, int *iX, int *iY )
  601. {
  602. // This is the offset from the topleft of the callout to the arrow tip
  603. const int iXOffset = XRES(25);
  604. const int iYOffset = YRES(50);
  605. //if ( engine->IsBoxInViewCluster( vMins + origin, vMaxs + origin) && !engine->CullBox( vMins + origin, vMaxs + origin ) )
  606. {
  607. if ( GetVectorInHudSpace( origin, *iX, *iY ) ) // TODO: GetVectorInHudSpace or GetVectorInScreenSpace?
  608. {
  609. *iX -= iXOffset;
  610. *iY -= iYOffset;
  611. int iRight = *iX + CALLOUT_WIDE;
  612. int iBottom = *iY + CALLOUT_TALL;
  613. if ( *iX > 0 && *iY > 0 && (iRight < ScreenWidth()) && (iBottom < (ScreenHeight()-YRES(40))) )
  614. {
  615. // Make sure it wouldn't be over the top of the freezepanel or statpanel
  616. Vector vecCalloutTL( *iX, *iY, 0 );
  617. Vector vecCalloutBR( iRight, iBottom, 1 );
  618. if ( !QuickBoxIntersectTest( vecCalloutTL, vecCalloutBR, vecFreezeTL, vecFreezeBR ) &&
  619. !QuickBoxIntersectTest( vecCalloutTL, vecCalloutBR, vecStatTL, vecStatBR ) )
  620. {
  621. // Make sure it doesn't intersect any other callouts
  622. bool bClear = true;
  623. for ( int iCall = 0; iCall < vecCalloutsTL->Count(); iCall++ )
  624. {
  625. if ( QuickBoxIntersectTest( vecCalloutTL, vecCalloutBR, vecCalloutsTL->Element(iCall), vecCalloutsBR->Element(iCall) ) )
  626. {
  627. bClear = false;
  628. break;
  629. }
  630. }
  631. if ( bClear )
  632. {
  633. // Verify that we have LOS to the gib
  634. trace_t tr;
  635. UTIL_TraceLine( origin, MainViewOrigin(), MASK_OPAQUE, NULL, COLLISION_GROUP_NONE, &tr );
  636. bClear = ( tr.fraction >= 1.0f );
  637. }
  638. if ( bClear )
  639. {
  640. CTFFreezePanelCallout *pCallout = new CTFFreezePanelCallout( g_pClientMode->GetViewport(), "FreezePanelCallout" );
  641. m_pCalloutPanels.AddToTail( vgui::SETUP_PANEL(pCallout) );
  642. vecCalloutsTL->AddToTail( vecCalloutTL );
  643. vecCalloutsBR->AddToTail( vecCalloutBR );
  644. pCallout->SetVisible( true );
  645. pCallout->SetBounds( *iX, *iY, CALLOUT_WIDE, CALLOUT_TALL );
  646. return pCallout;
  647. }
  648. }
  649. }
  650. }
  651. }
  652. return NULL;
  653. }
  654. //-----------------------------------------------------------------------------
  655. // Purpose:
  656. //-----------------------------------------------------------------------------
  657. void CTFFreezePanel::UpdateCallout( void )
  658. {
  659. CTFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
  660. if ( !pPlayer )
  661. return;
  662. // Abort early if we have no gibs or ragdoll
  663. CUtlVector<EHANDLE> *pGibList = pPlayer->GetSpawnedGibs();
  664. IRagdoll *pRagdoll = pPlayer->GetRepresentativeRagdoll();
  665. if ( (!pGibList || pGibList->Count() == 0) && !pRagdoll )
  666. return;
  667. if ( m_pFreezePanelBG == NULL )
  668. return;
  669. // Precalc the vectors of the freezepanel & statpanel
  670. int iX, iY;
  671. m_pFreezePanelBG->GetPos( iX, iY );
  672. Vector vecFreezeTL( iX, iY, 0 );
  673. Vector vecFreezeBR( iX + m_pFreezePanelBG->GetWide(), iY + m_pFreezePanelBG->GetTall(), 1 );
  674. CUtlVector<Vector> vecCalloutsTL;
  675. CUtlVector<Vector> vecCalloutsBR;
  676. Vector vecStatTL(0,0,0);
  677. Vector vecStatBR(0,0,1);
  678. CTFStatPanel *pStatPanel = GET_HUDELEMENT( CTFStatPanel );
  679. if ( pStatPanel && pStatPanel->IsVisible() )
  680. {
  681. pStatPanel->GetPos( iX, iY );
  682. vecStatTL.x = iX;
  683. vecStatTL.y = iY;
  684. vecStatBR.x = vecStatTL.x + pStatPanel->GetWide();
  685. vecStatBR.y = vecStatTL.y + pStatPanel->GetTall();
  686. }
  687. Vector vMins, vMaxs;
  688. // Check gibs
  689. if ( pGibList && pGibList->Count() )
  690. {
  691. int iCount = 0;
  692. for ( int i = 0; i < pGibList->Count(); i++ )
  693. {
  694. CBaseEntity *pGib = pGibList->Element(i);
  695. if ( pGib )
  696. {
  697. Vector origin = pGib->GetRenderOrigin();
  698. IPhysicsObject *pPhysicsObject = pGib->VPhysicsGetObject();
  699. if( pPhysicsObject )
  700. {
  701. Vector vecMassCenter = pPhysicsObject->GetMassCenterLocalSpace();
  702. pGib->CollisionProp()->CollisionToWorldSpace( vecMassCenter, &origin );
  703. }
  704. pGib->GetRenderBounds( vMins, vMaxs );
  705. // Try and add the callout
  706. CTFFreezePanelCallout *pCallout = TestAndAddCallout( origin, vMins, vMaxs, &vecCalloutsTL, &vecCalloutsBR,
  707. vecFreezeTL, vecFreezeBR, vecStatTL, vecStatBR, &iX, &iY );
  708. if ( pCallout )
  709. {
  710. pCallout->UpdateForGib( i, iCount );
  711. iCount++;
  712. }
  713. }
  714. }
  715. C_ObjectSentrygun *pSentry = dynamic_cast<C_ObjectSentrygun*>( ClientEntityList().GetEnt( GetSpectatorTarget() ) );
  716. if ( pSentry )
  717. {
  718. // A sentry was the killer...check and see if the builder is on screen.
  719. CTFPlayer *pBuilder = pSentry->GetBuilder();
  720. if ( pBuilder && GetVectorInHudSpace( pBuilder->GetRenderOrigin(), iX, iY ) ) // TODO: GetVectorInHudSpace or GetVectorInScreenSpace?
  721. {
  722. KeyValues *kv = new KeyValues( "FreezeCamTaunt" );
  723. kv->SetInt( "achiever", pBuilder->GetUserID() );
  724. kv->SetString( "command", "freezecam_tauntsentry" );
  725. engine->ServerCmdKeyValues( kv );
  726. }
  727. }
  728. // Tell the server that we saw some gibs onscreen
  729. if ( iCount > 0 )
  730. {
  731. SendTauntAcknowledgement( "freezecam_tauntgibs", iCount );
  732. }
  733. }
  734. // Check for a ragdoll as well. Dying characters that ragdoll can also drop wearable items as gibs
  735. if ( pRagdoll )
  736. {
  737. Vector origin = pRagdoll->GetRagdollOrigin();
  738. pRagdoll->GetRagdollBounds( vMins, vMaxs );
  739. // Try and add the callout
  740. CTFFreezePanelCallout *pCallout = TestAndAddCallout( origin, vMins, vMaxs, &vecCalloutsTL, &vecCalloutsBR,
  741. vecFreezeTL, vecFreezeBR, vecStatTL, vecStatBR, &iX, &iY );
  742. if ( pCallout )
  743. {
  744. pCallout->UpdateForRagdoll();
  745. }
  746. // even if the callout failed, check that our ragdoll is onscreen and our killer is taunting us (for an achievement)
  747. if ( GetVectorInHudSpace( origin, iX, iY ) ) // TODO: GetVectorInHudSpace or GetVectorInScreenSpace?
  748. {
  749. SendTauntAcknowledgement( "freezecam_tauntrag" );
  750. }
  751. }
  752. }
  753. //-----------------------------------------------------------------------------
  754. // Purpose:
  755. //-----------------------------------------------------------------------------
  756. void CTFFreezePanel::Show()
  757. {
  758. m_flShowCalloutsAt = 0;
  759. SetVisible( true );
  760. }
  761. void CTFFreezePanel::DeleteCalloutPanels()
  762. {
  763. for ( int i = m_pCalloutPanels.Count()-1; i >= 0; i-- )
  764. {
  765. m_pCalloutPanels[i]->MarkForDeletion();
  766. }
  767. m_pCalloutPanels.RemoveAll();
  768. }
  769. //-----------------------------------------------------------------------------
  770. // Purpose:
  771. //-----------------------------------------------------------------------------
  772. void CTFFreezePanel::Hide()
  773. {
  774. SetVisible( false );
  775. m_bHoldingAfterScreenshot = false;
  776. // Delete all our callout panels
  777. DeleteCalloutPanels();
  778. #if defined( REPLAY_ENABLED )
  779. // Explicitly set the replay reminder's visibility, which is not parented
  780. // to the freeze panel.
  781. if ( m_pSaveReplayPanel )
  782. {
  783. m_pSaveReplayPanel->SetVisible( false );
  784. }
  785. #endif
  786. }
  787. //-----------------------------------------------------------------------------
  788. // Purpose:
  789. //-----------------------------------------------------------------------------
  790. bool CTFFreezePanel::ShouldDraw( void )
  791. {
  792. return ( IsVisible() );
  793. }
  794. //-----------------------------------------------------------------------------
  795. // Purpose:
  796. //-----------------------------------------------------------------------------
  797. void CTFFreezePanel::OnThink( void )
  798. {
  799. BaseClass::OnThink();
  800. if ( m_pItemPanel && m_pItemPanel->IsVisible() )
  801. {
  802. CTFStatPanel *pStatPanel = GET_HUDELEMENT( CTFStatPanel );
  803. if ( pStatPanel && pStatPanel->IsVisible() )
  804. {
  805. m_pItemPanel->SetVisible( false );
  806. }
  807. }
  808. if ( m_flShowCalloutsAt && m_flShowCalloutsAt < gpGlobals->curtime )
  809. {
  810. if ( ShouldDraw() )
  811. {
  812. UpdateCallout();
  813. }
  814. m_flShowCalloutsAt = 0;
  815. }
  816. if ( m_flShowSnapshotReminderAt && m_flShowSnapshotReminderAt < gpGlobals->curtime )
  817. {
  818. if ( ShouldDraw() )
  819. {
  820. // For now don't do this in Steam Controller mode, because there's no easy way for a SC user to deal with this
  821. if ( !::input->IsSteamControllerActive() )
  822. {
  823. ShowSnapshotPanel( true );
  824. }
  825. }
  826. m_flShowSnapshotReminderAt = 0;
  827. }
  828. if ( m_flShowReplayReminderAt && m_flShowReplayReminderAt < gpGlobals->curtime )
  829. {
  830. if ( ShouldDraw() )
  831. {
  832. // For now don't do this in Steam Controller mode, because there's no easy way for a SC user to deal with this
  833. if ( !::input->IsSteamControllerActive() )
  834. {
  835. ShowSaveReplayPanel( true );
  836. }
  837. }
  838. m_flShowReplayReminderAt = 0;
  839. }
  840. }
  841. //-----------------------------------------------------------------------------
  842. // Purpose:
  843. //-----------------------------------------------------------------------------
  844. void CTFFreezePanel::ShowSnapshotPanelIn( float flTime )
  845. {
  846. #if defined (_X360 )
  847. return;
  848. #endif
  849. m_flShowSnapshotReminderAt = gpGlobals->curtime + flTime;
  850. }
  851. //-----------------------------------------------------------------------------
  852. // Purpose:
  853. //-----------------------------------------------------------------------------
  854. void CTFFreezePanel::ShowSaveReplayPanelIn( float flTime )
  855. {
  856. #if defined (_X360 )
  857. return;
  858. #endif
  859. m_flShowReplayReminderAt = gpGlobals->curtime + flTime;
  860. }
  861. //-----------------------------------------------------------------------------
  862. // Purpose:
  863. //-----------------------------------------------------------------------------
  864. void CTFFreezePanel::ShowSnapshotPanel( bool bShow )
  865. {
  866. if ( !m_pScreenshotPanel )
  867. return;
  868. const char *key = engine->Key_LookupBinding( "screenshot" );
  869. if ( key == NULL || FStrEq( key, "(null)" ) )
  870. {
  871. bShow = false;
  872. key = " ";
  873. }
  874. if ( bShow )
  875. {
  876. char szKey[16];
  877. Q_snprintf( szKey, sizeof(szKey), "%s", key );
  878. wchar_t wKey[16];
  879. wchar_t wLabel[256];
  880. g_pVGuiLocalize->ConvertANSIToUnicode(szKey, wKey, sizeof(wKey));
  881. g_pVGuiLocalize->ConstructString_safe( wLabel, g_pVGuiLocalize->Find("#TF_freezecam_snapshot" ), 1, wKey );
  882. m_pScreenshotPanel->SetDialogVariable( "text", wLabel );
  883. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudSnapShotReminderIn" );
  884. }
  885. m_pScreenshotPanel->SetVisible( bShow );
  886. }
  887. //-----------------------------------------------------------------------------
  888. // Purpose:
  889. //-----------------------------------------------------------------------------
  890. void CTFFreezePanel::ShowSaveReplayPanel( bool bShow )
  891. {
  892. #if defined( REPLAY_ENABLED )
  893. // Make sure ptr's ok
  894. if ( !m_pSaveReplayPanel )
  895. return;
  896. // Don't do this for Steam Controller users
  897. if ( ::input->IsSteamControllerActive() )
  898. return;
  899. // Make sure we're recording
  900. if ( !g_pReplay->IsRecording() )
  901. return;
  902. // Start animation if necessary
  903. if ( bShow )
  904. {
  905. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pSaveReplayPanel->GetParent(), "HudReplayReminderIn2" );
  906. }
  907. // Setup visibility
  908. m_pSaveReplayPanel->SetVisible( bShow );
  909. #endif
  910. }
  911. const char *CTFFreezePanel::GetFilesafePlayerName( const char *pszOldName )
  912. {
  913. if ( !pszOldName )
  914. return "";
  915. static char szSafeName[ MAX_PLAYER_NAME_LENGTH ];
  916. int nSafeNameBufSize = sizeof( szSafeName );
  917. int nNewPos = 0;
  918. for( const char *p = pszOldName; *p != 0 && nNewPos < nSafeNameBufSize-1; p++ )
  919. {
  920. if( *p == '.' )
  921. {
  922. szSafeName[ nNewPos ] = '-';
  923. }
  924. else if( *p == '/' )
  925. {
  926. szSafeName[ nNewPos ] = '-';
  927. }
  928. else if( *p == '\\' )
  929. {
  930. szSafeName[ nNewPos ] = '-';
  931. }
  932. else if( *p == ':' )
  933. {
  934. szSafeName[ nNewPos ] = '-';
  935. }
  936. else
  937. {
  938. szSafeName[ nNewPos ] = *p;
  939. }
  940. nNewPos++;
  941. }
  942. szSafeName[ nNewPos ] = 0;
  943. return szSafeName;
  944. }
  945. int CTFFreezePanel::HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
  946. {
  947. if ( ShouldDraw() && pszCurrentBinding )
  948. {
  949. if ( FStrEq( pszCurrentBinding, "screenshot" ) || FStrEq( pszCurrentBinding, "jpeg" ) )
  950. {
  951. // move the target id to the corner
  952. if ( m_pBasePanel && m_bShouldScreenshotMovePanelToCorner )
  953. {
  954. int w, h;
  955. m_pBasePanel->GetSize( w, h );
  956. if ( m_pItemPanel && m_pItemPanel->IsVisible() )
  957. {
  958. int iw,ih;
  959. m_pItemPanel->GetSize( iw, ih );
  960. m_pItemPanel->SetPos( ScreenWidth() - iw, ScreenHeight() - ih );
  961. m_pBasePanel->SetPos( ScreenWidth() - w, ScreenHeight() - ih - h );
  962. }
  963. else
  964. {
  965. m_pBasePanel->SetPos( ScreenWidth() - w, ScreenHeight() - h );
  966. }
  967. }
  968. // Get the local player.
  969. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  970. if ( pPlayer )
  971. {
  972. //Do effects
  973. g_flFreezeFlash = gpGlobals->curtime + 0.75f;
  974. pPlayer->EmitSound( "Camera.SnapShot" );
  975. //Extend Freezecam by a couple more seconds.
  976. engine->ClientCmd( "extendfreeze" );
  977. view->FreezeFrame( 3.0f );
  978. //Hide the reminder panel
  979. m_flShowSnapshotReminderAt = 0;
  980. ShowSnapshotPanel( false );
  981. // Hide replay reminder panel
  982. m_flShowReplayReminderAt = 0;
  983. ShowSaveReplayPanel( false );
  984. m_bHoldingAfterScreenshot = true;
  985. // Hide everything?
  986. if ( hud_freezecamhide.GetBool() )
  987. {
  988. SetVisible( false );
  989. DeleteCalloutPanels();
  990. }
  991. //Set the screenshot name
  992. if ( m_iKillerIndex <= MAX_PLAYERS )
  993. {
  994. const char *pszKillerName = g_PR->GetPlayerName( m_iKillerIndex );
  995. if ( pszKillerName )
  996. {
  997. ConVarRef cl_screenshotname( "cl_screenshotname" );
  998. if ( cl_screenshotname.IsValid() )
  999. {
  1000. char szScreenShotName[512];
  1001. Q_snprintf( szScreenShotName, sizeof( szScreenShotName ), "%s %s", GetFilesafePlayerName( pszKillerName ), FREEZECAM_SCREENSHOT_STRING );
  1002. cl_screenshotname.SetValue( szScreenShotName );
  1003. }
  1004. }
  1005. C_TFPlayer *pKiller = ToTFPlayer( UTIL_PlayerByIndex( m_iKillerIndex ) );
  1006. if ( pKiller )
  1007. {
  1008. CSteamID steamID;
  1009. if ( pKiller->GetSteamID( &steamID ) )
  1010. {
  1011. ConVarRef cl_screenshotusertag( "cl_screenshotusertag" );
  1012. if ( cl_screenshotusertag.IsValid() )
  1013. {
  1014. cl_screenshotusertag.SetValue( (int)steamID.GetAccountID() );
  1015. }
  1016. }
  1017. }
  1018. }
  1019. }
  1020. }
  1021. #if defined( REPLAY_ENABLED )
  1022. else if ( FStrEq (pszCurrentBinding, "save_replay" ) )
  1023. {
  1024. m_flShowReplayReminderAt = 0;
  1025. ShowSaveReplayPanel( false );
  1026. }
  1027. #endif
  1028. }
  1029. return 0;
  1030. }
  1031. //-----------------------------------------------------------------------------
  1032. // Purpose: Shows or hides the nemesis part of the panel
  1033. //-----------------------------------------------------------------------------
  1034. void CTFFreezePanel::ShowNemesisPanel( bool bShow )
  1035. {
  1036. if ( !m_pNemesisSubPanel )
  1037. return;
  1038. m_pNemesisSubPanel->SetVisible( bShow );
  1039. if ( bShow )
  1040. {
  1041. vgui::Label *pLabel = dynamic_cast< vgui::Label *>( m_pNemesisSubPanel->FindChildByName( "NemesisLabel" ) );
  1042. vgui::Label *pLabel2 = dynamic_cast< vgui::Label *>( m_pNemesisSubPanel->FindChildByName( "NemesisLabel2" ) );
  1043. vgui::Panel *pBG = m_pNemesisSubPanel->FindChildByName( "NemesisPanelBG" );
  1044. vgui::ImagePanel *pIcon = dynamic_cast< vgui::ImagePanel *>( m_pNemesisSubPanel->FindChildByName( "NemesisIcon" ) );
  1045. // check that our Nemesis panel and resize it to the length of the string (the right side is pinned and doesn't move)
  1046. if ( pLabel && pLabel2 && pBG && pIcon )
  1047. {
  1048. int nDiffX, nDiffY;
  1049. int wide, tall;
  1050. if ( !pLabel2->IsVisible() )
  1051. {
  1052. pLabel->GetContentSize( wide, tall );
  1053. nDiffX = wide - pLabel->GetWide();
  1054. nDiffY = tall - pLabel->GetTall();
  1055. }
  1056. else
  1057. {
  1058. pLabel2->GetContentSize( wide, tall );
  1059. nDiffX = wide - pLabel2->GetWide();
  1060. nDiffY = tall - pLabel2->GetTall();
  1061. }
  1062. if ( nDiffX != 0 || nDiffY != 0 )
  1063. {
  1064. int x, y, w, t;
  1065. // move the icon
  1066. pIcon->GetBounds( x, y, w, t );
  1067. pIcon->SetBounds( x - nDiffX, y - nDiffY, w, t );
  1068. pLabel->GetBounds( x, y, w, t );
  1069. pLabel->SetBounds( x - nDiffX, y - nDiffY, w + nDiffX, t + nDiffY );
  1070. pLabel2->GetBounds( x, y, w, t );
  1071. pLabel2->SetBounds( x - nDiffX, y - nDiffY, w + nDiffX, t + nDiffY );
  1072. // move/resize the background
  1073. pBG->GetBounds( x, y, w, t );
  1074. pBG->SetBounds( x - nDiffX, y - nDiffY, w + nDiffX, t + nDiffY );
  1075. m_pNemesisSubPanel->GetBounds( x, y, w, t );
  1076. m_pNemesisSubPanel->SetBounds( x, y - nDiffY, w, t + nDiffY );
  1077. }
  1078. }
  1079. }
  1080. }
  1081. //-----------------------------------------------------------------------------
  1082. // Purpose:
  1083. //-----------------------------------------------------------------------------
  1084. CTFFreezePanelCallout::CTFFreezePanelCallout( Panel *parent, const char *name ) : EditablePanel(parent,name)
  1085. {
  1086. m_pGibLabel = NULL;
  1087. }
  1088. //-----------------------------------------------------------------------------
  1089. // Purpose: Applies scheme settings
  1090. //-----------------------------------------------------------------------------
  1091. void CTFFreezePanelCallout::ApplySchemeSettings( vgui::IScheme *pScheme )
  1092. {
  1093. BaseClass::ApplySchemeSettings( pScheme );
  1094. LoadControlSettings( "resource/UI/FreezePanelCallout.res" );
  1095. m_pGibLabel = dynamic_cast<Label *>( FindChildByName("CalloutLabel") );
  1096. }
  1097. const char *pszCalloutGibNames[] =
  1098. {
  1099. "#Callout_Head",
  1100. "#Callout_Foot",
  1101. "#Callout_Hand",
  1102. "#Callout_Torso",
  1103. NULL, // Random
  1104. };
  1105. const char *pszCalloutRandomGibNames[] =
  1106. {
  1107. "#Callout_Organ2",
  1108. "#Callout_Organ3",
  1109. "#Callout_Organ4",
  1110. "#Callout_Organ5",
  1111. "#Callout_Organ6",
  1112. };
  1113. //-----------------------------------------------------------------------------
  1114. // Purpose:
  1115. //-----------------------------------------------------------------------------
  1116. void CTFFreezePanelCallout::UpdateForGib( int iGib, int iCount )
  1117. {
  1118. if ( !m_pGibLabel )
  1119. return;
  1120. if ( iGib < ARRAYSIZE(pszCalloutGibNames) )
  1121. {
  1122. if ( pszCalloutGibNames[iGib] )
  1123. {
  1124. m_pGibLabel->SetText( pszCalloutGibNames[iGib] );
  1125. }
  1126. else
  1127. {
  1128. m_pGibLabel->SetText( pszCalloutRandomGibNames[ RandomInt(0,ARRAYSIZE(pszCalloutRandomGibNames)-1) ] );
  1129. }
  1130. }
  1131. else
  1132. {
  1133. if ( iCount > 1 )
  1134. {
  1135. m_pGibLabel->SetText( "#FreezePanel_Callout3" );
  1136. }
  1137. else if ( iCount == 1 )
  1138. {
  1139. m_pGibLabel->SetText( "#FreezePanel_Callout2" );
  1140. }
  1141. else
  1142. {
  1143. m_pGibLabel->SetText( "#FreezePanel_Callout" );
  1144. }
  1145. }
  1146. #ifndef _X360
  1147. int wide, tall;
  1148. m_pGibLabel->GetContentSize( wide, tall );
  1149. // is the text wider than the label?
  1150. if ( wide > m_pGibLabel->GetWide() )
  1151. {
  1152. int nDiff = wide - m_pGibLabel->GetWide();
  1153. int x, y, w, t;
  1154. // make the label wider
  1155. m_pGibLabel->GetBounds( x, y, w, t );
  1156. m_pGibLabel->SetBounds( x, y, w + nDiff, t );
  1157. vgui::Panel *pBackground = FindChildByName( "CalloutBG" );
  1158. if ( pBackground )
  1159. {
  1160. // also adjust the background image
  1161. pBackground->GetBounds( x, y, w, t );
  1162. pBackground->SetBounds( x, y, w + nDiff, t );
  1163. }
  1164. // make ourselves bigger to accommodate the wider children
  1165. GetBounds( x, y, w, t );
  1166. SetBounds( x, y, w + nDiff, t );
  1167. // check that we haven't run off the right side of the screen
  1168. if ( x + GetWide() > ScreenWidth() )
  1169. {
  1170. // push ourselves to the left to fit on the screen
  1171. nDiff = ( x + GetWide() ) - ScreenWidth();
  1172. SetPos( x - nDiff, y );
  1173. // push the arrow to the right to offset moving ourselves to the left
  1174. vgui::ImagePanel *pArrow = dynamic_cast<ImagePanel *>( FindChildByName( "ArrowIcon" ) );
  1175. if ( pArrow )
  1176. {
  1177. pArrow->GetBounds( x, y, w, t );
  1178. pArrow->SetBounds( x + nDiff, y, w, t );
  1179. }
  1180. }
  1181. }
  1182. #endif
  1183. }
  1184. //-----------------------------------------------------------------------------
  1185. // Purpose:
  1186. //-----------------------------------------------------------------------------
  1187. void CTFFreezePanelCallout::UpdateForRagdoll( void )
  1188. {
  1189. if ( !m_pGibLabel )
  1190. return;
  1191. m_pGibLabel->SetText( "#Callout_Ragdoll" );
  1192. }