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.

300 lines
8.6 KiB

  1. //========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Draws the death notices
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "hud_macros.h"
  9. #include "hudelement.h"
  10. #include "c_playerresource.h"
  11. #include "iclientmode.h"
  12. #include <vgui_controls/controls.h>
  13. #include <vgui_controls/Panel.h>
  14. #include <vgui/ISurface.h>
  15. #include <vgui/ILocalize.h>
  16. #include <game/client/iviewport.h>
  17. #include <igameevents.h>
  18. #include <keyvalues.h>
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. //-----------------------------------------------------------------------------
  22. // Purpose:
  23. //-----------------------------------------------------------------------------
  24. class CHudDeathNotice : public CHudElement, public vgui::Panel
  25. {
  26. DECLARE_CLASS_SIMPLE( CHudDeathNotice, vgui::Panel );
  27. public:
  28. explicit CHudDeathNotice( const char *pElementName );
  29. void Init( void );
  30. void VidInit( void );
  31. bool ShouldDraw( void );
  32. virtual void Paint();
  33. virtual void ApplySchemeSettings( vgui::IScheme *scheme );
  34. void FireGameEvent( KeyValues * event);
  35. private:
  36. CHudTexture *m_iconD_skull; // sprite index of skull icon
  37. vgui::HFont m_hTextFont;
  38. Color m_clrText;
  39. };
  40. using namespace vgui;
  41. //
  42. //-----------------------------------------------------
  43. //
  44. DECLARE_HUDELEMENT( CHudDeathNotice );
  45. //-----------------------------------------------------------------------------
  46. // Purpose:
  47. //-----------------------------------------------------------------------------
  48. CHudDeathNotice::CHudDeathNotice( const char *pElementName ) :
  49. CHudElement( pElementName ), BaseClass( NULL, "HudDeathNotice" )
  50. {
  51. vgui::Panel *pParent = GetClientMode()->GetViewport();
  52. SetParent( pParent );
  53. SetHiddenBits( HIDEHUD_MISCSTATUS );
  54. }
  55. void CHudDeathNotice::ApplySchemeSettings( IScheme *scheme )
  56. {
  57. BaseClass::ApplySchemeSettings( scheme );
  58. m_hTextFont = scheme->GetFont( "HudNumbersSmall" );
  59. m_clrText = scheme->GetColor( "FgColor", GetFgColor() );
  60. SetPaintBackgroundEnabled( false );
  61. }
  62. //-----------------------------------------------------
  63. struct DeathNoticeItem {
  64. char szKiller[MAX_PLAYER_NAME_LENGTH];
  65. char szVictim[MAX_PLAYER_NAME_LENGTH];
  66. CHudTexture *iconDeath; // the index number of the associated sprite
  67. int iSuicide;
  68. int iTeamKill;
  69. float flDisplayTime;
  70. };
  71. #define MAX_DEATHNOTICES 4
  72. static int DEATHNOTICE_DISPLAY_TIME = 6;
  73. // Robin HACKHACK: HL2 doesn't use deathmsgs, so I just forced these down below our minimap.
  74. // It should be positioned by TF2/HL2 separately, and TF2 should position it according to the minimap position
  75. #define DEATHNOTICE_TOP YRES( 140 ) // Was: 20
  76. DeathNoticeItem rgDeathNoticeList[ MAX_DEATHNOTICES + 1 ];
  77. static ConVar hud_deathnotice_time( "hud_deathnotice_time", "6", 0 );
  78. //-----------------------------------------------------------------------------
  79. // Purpose:
  80. //-----------------------------------------------------------------------------
  81. void CHudDeathNotice::Init( void )
  82. {
  83. memset( rgDeathNoticeList, 0, sizeof(rgDeathNoticeList) );
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Purpose:
  87. //-----------------------------------------------------------------------------
  88. void CHudDeathNotice::VidInit( void )
  89. {
  90. m_iconD_skull = HudIcons().GetIcon( "d_skull" );
  91. }
  92. //-----------------------------------------------------------------------------
  93. // Purpose: Draw if we've got at least one death notice in the queue
  94. //-----------------------------------------------------------------------------
  95. bool CHudDeathNotice::ShouldDraw( void )
  96. {
  97. return ( CHudElement::ShouldDraw() && ( rgDeathNoticeList[0].iconDeath ) );
  98. }
  99. //-----------------------------------------------------------------------------
  100. // Purpose:
  101. //-----------------------------------------------------------------------------
  102. void CHudDeathNotice::Paint()
  103. {
  104. int x, y;
  105. surface()->DrawSetTextFont( m_hTextFont );
  106. surface()->DrawSetTextColor( m_clrText );
  107. for ( int i = 0; i < MAX_DEATHNOTICES; i++ )
  108. {
  109. // we've gone through them all
  110. if ( rgDeathNoticeList[i].iconDeath == NULL )
  111. break;
  112. // display time has expired
  113. // remove the current item from the list
  114. if ( rgDeathNoticeList[i].flDisplayTime < gpGlobals->curtime )
  115. {
  116. Q_memmove( &rgDeathNoticeList[i], &rgDeathNoticeList[i+1], sizeof(DeathNoticeItem) * (MAX_DEATHNOTICES - i) );
  117. // continue on the next item; stop the counter getting incremented
  118. i--;
  119. continue;
  120. }
  121. rgDeathNoticeList[i].flDisplayTime = MIN( rgDeathNoticeList[i].flDisplayTime, gpGlobals->curtime + DEATHNOTICE_DISPLAY_TIME );
  122. // Draw the death notice
  123. y = DEATHNOTICE_TOP + (20 * i) + 100; //!!!
  124. CHudTexture *icon = rgDeathNoticeList[i].iconDeath;
  125. if ( !icon )
  126. continue;
  127. wchar_t victim[ 256 ];
  128. wchar_t killer[ 256 ];
  129. g_pVGuiLocalize->ConvertANSIToUnicode( rgDeathNoticeList[i].szVictim, victim, sizeof( victim ) );
  130. g_pVGuiLocalize->ConvertANSIToUnicode( rgDeathNoticeList[i].szKiller, killer, sizeof( killer ) );
  131. int len = UTIL_ComputeStringWidth( m_hTextFont, victim );
  132. x = ScreenWidth() - len - icon->Width() - 5;
  133. if ( !rgDeathNoticeList[i].iSuicide )
  134. {
  135. int lenkiller = UTIL_ComputeStringWidth( m_hTextFont, killer );
  136. x -= (5 + lenkiller );
  137. // Draw killer's name
  138. surface()->DrawSetTextPos( x, y );
  139. surface()->DrawUnicodeString( killer );
  140. surface()->DrawGetTextPos( x, y );
  141. x += 5;
  142. }
  143. Color iconColor( 255, 80, 0, 255 );
  144. if ( rgDeathNoticeList[i].iTeamKill )
  145. {
  146. // display it in sickly green
  147. iconColor = Color( 10, 240, 10, 255 );
  148. }
  149. // Draw death weapon
  150. icon->DrawSelf( x, y, iconColor );
  151. x += icon->Width();
  152. // Draw victims name
  153. surface()->DrawSetTextPos( x, y );
  154. surface()->DrawUnicodeString( victim );
  155. }
  156. }
  157. //-----------------------------------------------------------------------------
  158. // Purpose: This message handler may be better off elsewhere
  159. //-----------------------------------------------------------------------------
  160. void CHudDeathNotice::FireGameEvent( KeyValues * event)
  161. {
  162. // Got message during connection
  163. if ( !g_PR )
  164. return;
  165. int killer = engine->GetPlayerForUserID( event->GetInt("killer") );
  166. int victim = engine->GetPlayerForUserID( event->GetInt("victim") );
  167. char killedwith[32];
  168. Q_snprintf( killedwith, sizeof( killedwith ), "d_%s", event->GetString("weapon") );
  169. int i;
  170. for ( i = 0; i < MAX_DEATHNOTICES; i++ )
  171. {
  172. if ( rgDeathNoticeList[i].iconDeath == NULL )
  173. break;
  174. }
  175. if ( i == MAX_DEATHNOTICES )
  176. { // move the rest of the list forward to make room for this item
  177. Q_memmove( rgDeathNoticeList, rgDeathNoticeList+1, sizeof(DeathNoticeItem) * MAX_DEATHNOTICES );
  178. i = MAX_DEATHNOTICES - 1;
  179. }
  180. // Get the names of the players
  181. const char *killer_name = g_PR->GetPlayerName( killer );
  182. const char *victim_name = g_PR->GetPlayerName( victim );
  183. if ( !killer_name )
  184. killer_name = "";
  185. if ( !victim_name )
  186. victim_name = "";
  187. Q_strncpy( rgDeathNoticeList[i].szKiller, killer_name, MAX_PLAYER_NAME_LENGTH );
  188. Q_strncpy( rgDeathNoticeList[i].szVictim, victim_name, MAX_PLAYER_NAME_LENGTH );
  189. if ( killer == victim || killer == 0 )
  190. rgDeathNoticeList[i].iSuicide = true;
  191. if ( !strcmp( killedwith, "d_teammate" ) )
  192. rgDeathNoticeList[i].iTeamKill = true;
  193. // try and find the death identifier in the icon list
  194. rgDeathNoticeList[i].iconDeath = HudIcons().GetIcon( killedwith );
  195. if ( !rgDeathNoticeList[i].iconDeath )
  196. {
  197. // can't find it, so use the default skull & crossbones icon
  198. rgDeathNoticeList[i].iconDeath = m_iconD_skull;
  199. }
  200. DEATHNOTICE_DISPLAY_TIME = hud_deathnotice_time.GetFloat();
  201. rgDeathNoticeList[i].flDisplayTime = gpGlobals->curtime + DEATHNOTICE_DISPLAY_TIME;
  202. // record the death notice in the console
  203. if ( rgDeathNoticeList[i].iSuicide )
  204. {
  205. Msg( "%s", rgDeathNoticeList[i].szVictim );
  206. if ( !strcmp( killedwith, "d_world" ) )
  207. {
  208. Msg( " died" );
  209. }
  210. else
  211. {
  212. Msg( " killed self" );
  213. }
  214. }
  215. else if ( rgDeathNoticeList[i].iTeamKill )
  216. {
  217. Msg( "%s", rgDeathNoticeList[i].szKiller );
  218. Msg( " killed his teammate " );
  219. Msg( "%s", rgDeathNoticeList[i].szVictim );
  220. }
  221. else
  222. {
  223. Msg( "%s", rgDeathNoticeList[i].szKiller );
  224. Msg( " killed " );
  225. Msg( "%s", rgDeathNoticeList[i].szVictim );
  226. }
  227. if ( killedwith && *killedwith && (*killedwith > 13 ) && strcmp( killedwith, "d_world" ) && !rgDeathNoticeList[i].iTeamKill )
  228. {
  229. Msg( " with " );
  230. // replace the code names with the 'real' names
  231. if ( !strcmp( killedwith+2, "egon" ) )
  232. Q_strncpy( killedwith, "d_gluon gun", sizeof( killedwith ) );
  233. if ( !strcmp( killedwith+2, "gauss" ) )
  234. Q_strncpy( killedwith, "d_tau cannon", sizeof( killedwith ) );
  235. Msg( killedwith+2 ); // skip over the "d_" part
  236. }
  237. Msg( "\n" );
  238. }