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.

383 lines
9.5 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "dod_hud_deathstats.h"
  9. #include "vgui_controls/AnimationController.h"
  10. #include "iclientmode.h"
  11. #include <vgui_controls/Label.h>
  12. #include <vgui/ILocalize.h>
  13. #include <vgui/ISurface.h>
  14. #include "hud_macros.h"
  15. #include "c_dod_playerresource.h"
  16. #include "c_dod_team.h"
  17. #include "c_dod_player.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. extern ConVar cl_deathicon_width;
  21. extern ConVar cl_deathicon_height;
  22. //DECLARE_HUDELEMENT( CDODDeathStatsPanel );
  23. //-----------------------------------------------------------------------------
  24. // Purpose: Constructor
  25. //-----------------------------------------------------------------------------
  26. CDODDeathStatsPanel::CDODDeathStatsPanel( const char *pElementName )
  27. : EditablePanel( NULL, "DeathStats" ), CHudElement( pElementName )
  28. {
  29. vgui::Panel *pParent = g_pClientMode->GetViewport();
  30. SetParent( pParent );
  31. SetVisible( false );
  32. SetAlpha( 0 );
  33. SetScheme( "ClientScheme" );
  34. m_pAttackerHistoryLabel = new vgui::Label( this, "AttackerDmgLabel", "..." );
  35. m_pSummaryLabel = new vgui::Label( this, "LifeSummaryLabel", "..." );
  36. memset( &m_DeathRecord, 0, sizeof(m_DeathRecord) );
  37. LoadControlSettings("Resource/UI/DeathStats.res");
  38. }
  39. void CDODDeathStatsPanel::OnScreenSizeChanged( int iOldWide, int iOldTall )
  40. {
  41. LoadControlSettings( "resource/UI/DeathStats.res" );
  42. }
  43. void CDODDeathStatsPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
  44. {
  45. BaseClass::ApplySchemeSettings( pScheme );
  46. SetBgColor( GetSchemeColor("TransparentLightBlack", pScheme) );
  47. }
  48. //-----------------------------------------------------------------------------
  49. // Purpose:
  50. //-----------------------------------------------------------------------------
  51. void CDODDeathStatsPanel::Reset()
  52. {
  53. Hide();
  54. }
  55. void CDODDeathStatsPanel::Init()
  56. {
  57. Hide();
  58. ListenForGameEvent( "player_death" );
  59. m_iMaterialTexture = vgui::surface()->CreateNewTextureID();
  60. CHudElement::Init();
  61. }
  62. void CDODDeathStatsPanel::VidInit( void )
  63. {
  64. m_iconD_skull = gHUD.GetIcon( "d_skull_dod" );
  65. m_pIconKill = gHUD.GetIcon( "stats_kill" );
  66. m_pIconWounded = gHUD.GetIcon( "stats_wounded" );
  67. m_pIconCap = gHUD.GetIcon( "stats_cap" );
  68. m_pIconDefended = gHUD.GetIcon( "stats_defended" );
  69. }
  70. //-----------------------------------------------------------------------------
  71. // Purpose: Handle player_death message
  72. //-----------------------------------------------------------------------------
  73. void CDODDeathStatsPanel::FireGameEvent( IGameEvent * event)
  74. {
  75. if ( Q_strcmp( "player_death", event->GetName() ) == 0 )
  76. {
  77. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  78. if ( !pLocalPlayer )
  79. return;
  80. if ( !g_PR )
  81. return;
  82. int victim = engine->GetPlayerForUserID( event->GetInt("userid") );
  83. // only deal with deathnotices where we die
  84. if ( victim != pLocalPlayer->entindex() )
  85. {
  86. return;
  87. }
  88. int killer = engine->GetPlayerForUserID( event->GetInt("attacker") );
  89. const char *killedwith = event->GetString( "weapon" );
  90. char fullkilledwith[128];
  91. if ( killedwith && *killedwith )
  92. {
  93. Q_snprintf( fullkilledwith, sizeof(fullkilledwith), "d_%s", killedwith );
  94. }
  95. else
  96. {
  97. fullkilledwith[0] = 0;
  98. }
  99. // Get the names of the players
  100. const char *killer_name = g_PR->GetPlayerName( killer );
  101. const char *victim_name = g_PR->GetPlayerName( victim );
  102. if ( !killer_name )
  103. killer_name = "";
  104. if ( !victim_name )
  105. victim_name = "";
  106. m_DeathRecord.Killer.iEntIndex = killer;
  107. m_DeathRecord.Victim.iEntIndex = victim;
  108. Q_strncpy( m_DeathRecord.Killer.szName, killer_name, MAX_PLAYER_NAME_LENGTH );
  109. Q_strncpy( m_DeathRecord.Victim.szName, victim_name, MAX_PLAYER_NAME_LENGTH );
  110. m_DeathRecord.bSuicide = ( !killer || killer == victim );
  111. // Try and find the death identifier in the icon list
  112. m_DeathRecord.iconDeath = gHUD.GetIcon( fullkilledwith );
  113. if ( !m_DeathRecord.iconDeath )
  114. {
  115. // Can't find it, so use the default skull & crossbones icon
  116. m_DeathRecord.iconDeath = m_iconD_skull;
  117. }
  118. // Info we get from this message:
  119. // - who killed us with what
  120. // Info that is networked to the local player
  121. // - the hitgroups we hit the guy who killed us with
  122. // - life kills
  123. // - life woundings
  124. // - life caps
  125. // - life defenses
  126. Show();
  127. }
  128. }
  129. const char *szHitgroupNames[] =
  130. {
  131. "head",
  132. "chest",
  133. "arm",
  134. "leg"
  135. };
  136. void CDODDeathStatsPanel::Paint( void )
  137. {
  138. int deathNoticeWidth = 0;
  139. if ( m_DeathRecord.Victim.iEntIndex > 0 )
  140. deathNoticeWidth = DrawDeathNoticeItem( m_iDeathNoticeX, m_iDeathNoticeY );
  141. const int minWidth = XRES(160);
  142. int panelWidth = ( deathNoticeWidth < minWidth ? minWidth : deathNoticeWidth );
  143. int wide, tall;
  144. // set width of summary label to death notice width
  145. m_pSummaryLabel->GetSize( wide, tall );
  146. m_pSummaryLabel->SetSize( panelWidth, tall );
  147. C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer();
  148. if ( !pLocalPlayer )
  149. return;
  150. char buf[512];
  151. buf[0] = '\0';
  152. if ( !m_DeathRecord.bSuicide )
  153. {
  154. bool bStart = true;
  155. bool bHit = false;
  156. for ( int i=0;i<4;i++ )
  157. {
  158. if ( pLocalPlayer->m_iHitsOnAttacker[i] > 0 )
  159. {
  160. bHit = true;
  161. if ( bStart )
  162. {
  163. Q_snprintf( buf, sizeof(buf), "You hit %s %i %s in the %s\n",
  164. m_DeathRecord.Killer.szName,
  165. pLocalPlayer->m_iHitsOnAttacker[i],
  166. pLocalPlayer->m_iHitsOnAttacker[i] == 1 ? "time" : "times",
  167. szHitgroupNames[i] );
  168. bStart = false;
  169. }
  170. else
  171. {
  172. Q_snprintf( buf, sizeof(buf), "%s and %i %s in the %s\n",
  173. buf,
  174. pLocalPlayer->m_iHitsOnAttacker[i],
  175. pLocalPlayer->m_iHitsOnAttacker[i] == 1 ? "time" : "times",
  176. szHitgroupNames[i] );
  177. }
  178. }
  179. }
  180. }
  181. Q_strncat( buf, "\n", sizeof(buf), COPY_ALL_CHARACTERS );
  182. if ( pLocalPlayer->m_iPerLifeKills )
  183. {
  184. Q_snprintf( buf, sizeof(buf), "%sKills: %i\n\n",
  185. buf,
  186. pLocalPlayer->m_iPerLifeKills );
  187. }
  188. if ( pLocalPlayer->m_iPerLifeWounded )
  189. {
  190. Q_snprintf( buf, sizeof(buf), "%sWounded: %i\n\n",
  191. buf,
  192. pLocalPlayer->m_iPerLifeWounded );
  193. }
  194. if ( pLocalPlayer->m_iPerLifeCaptures )
  195. {
  196. Q_snprintf( buf, sizeof(buf), "%sFlag Captures: %i\n\n",
  197. buf,
  198. pLocalPlayer->m_iPerLifeCaptures );
  199. }
  200. if ( pLocalPlayer->m_iPerLifeDefenses )
  201. {
  202. Q_snprintf( buf, sizeof(buf), "%sFlag Defenses: %i\n\n",
  203. buf,
  204. pLocalPlayer->m_iPerLifeDefenses );
  205. }
  206. m_pAttackerHistoryLabel->SetText( buf );
  207. m_pAttackerHistoryLabel->SizeToContents();
  208. int panel_h = YRES(160);
  209. SetSize( panelWidth, panel_h );
  210. }
  211. float GetScale( int nIconWidth, int nIconHeight, int nWidth, int nHeight );
  212. int CDODDeathStatsPanel::DrawDeathNoticeItem( int x, int y )
  213. {
  214. // Get the team numbers for the players involved
  215. int iKillerTeam = TEAM_UNASSIGNED;
  216. int iVictimTeam = TEAM_UNASSIGNED;
  217. if( g_PR )
  218. {
  219. iKillerTeam = g_PR->GetTeam( m_DeathRecord.Killer.iEntIndex );
  220. iVictimTeam = g_PR->GetTeam( m_DeathRecord.Victim.iEntIndex );
  221. }
  222. wchar_t victim[ 256 ];
  223. wchar_t killer[ 256 ];
  224. g_pVGuiLocalize->ConvertANSIToUnicode( m_DeathRecord.Victim.szName, victim, sizeof( victim ) );
  225. g_pVGuiLocalize->ConvertANSIToUnicode( m_DeathRecord.Killer.szName, killer, sizeof( killer ) );
  226. // Get the local position for this notice
  227. int len = UTIL_ComputeStringWidth( m_hTextFont, victim );
  228. int iconWide;
  229. int iconTall;
  230. CHudTexture *icon = m_DeathRecord.iconDeath;
  231. Assert( icon );
  232. if ( !icon )
  233. return 0;
  234. if( icon->bRenderUsingFont )
  235. {
  236. iconWide = surface()->GetCharacterWidth( icon->hFont, icon->cCharacterInFont );
  237. iconTall = surface()->GetFontTall( icon->hFont );
  238. }
  239. else
  240. {
  241. float scale = GetScale( icon->Width(), icon->Height(), XRES(cl_deathicon_width.GetInt()), YRES(cl_deathicon_height.GetInt()) );
  242. iconWide = (int)( scale * (float)icon->Width() );
  243. iconTall = (int)( scale * (float)icon->Height() );
  244. }
  245. int spacerX = XRES(5);
  246. //int x = xRight - len - spacerX - iconWide - XRES(10);
  247. surface()->DrawSetTextFont( m_hTextFont );
  248. int iFontTall = vgui::surface()->GetFontTall( m_hTextFont );
  249. int yText = y + ( iconTall - iFontTall ) / 2;
  250. int boxWidth = len + iconWide + spacerX;
  251. int boxHeight = MIN( iconTall, m_flLineHeight );
  252. int boxBorder = XRES(2);
  253. // Only draw killers name if it wasn't a suicide
  254. if ( !m_DeathRecord.bSuicide )
  255. {
  256. int nameWidth = UTIL_ComputeStringWidth( m_hTextFont, killer ) + spacerX; // gap
  257. //x -= nameWidth;
  258. boxWidth += nameWidth;
  259. Panel::DrawBox( x-boxBorder,
  260. y-boxBorder,
  261. boxWidth+2*boxBorder,
  262. boxHeight+2*boxBorder,
  263. m_ActiveBackgroundColor,
  264. 1.0 );
  265. Color c = g_PR->GetTeamColor( iKillerTeam );
  266. surface()->DrawSetTextColor( c );
  267. // Draw killer's name
  268. surface()->DrawSetTextPos( x, yText );
  269. const wchar_t *p = killer;
  270. while ( *p )
  271. {
  272. surface()->DrawUnicodeChar( *p++ );
  273. }
  274. surface()->DrawGetTextPos( x, yText );
  275. x += spacerX;
  276. }
  277. else
  278. {
  279. Panel::DrawBox( x-boxBorder,
  280. y-boxBorder,
  281. boxWidth+2*boxBorder,
  282. boxHeight+2*boxBorder,
  283. m_ActiveBackgroundColor,
  284. 1.0 );
  285. }
  286. Color iconColor( 255, 80, 0, 255 );
  287. // Draw death weapon
  288. //If we're using a font char, this will ignore iconTall and iconWide
  289. icon->DrawSelf( x, y, iconWide, iconTall, iconColor );
  290. x += iconWide + spacerX;
  291. Color c = g_PR->GetTeamColor( iVictimTeam );
  292. surface()->DrawSetTextColor( c );
  293. // Draw victims name
  294. surface()->DrawSetTextFont( m_hTextFont ); //reset the font, draw icon can change it
  295. surface()->DrawSetTextPos( x, yText );
  296. const wchar_t *p = victim;
  297. while ( *p )
  298. {
  299. surface()->DrawUnicodeChar( *p++ );
  300. }
  301. return boxWidth;
  302. }