//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "cbase.h" #include "dod_hud_deathstats.h" #include "vgui_controls/AnimationController.h" #include "iclientmode.h" #include #include #include #include "hud_macros.h" #include "c_dod_playerresource.h" #include "c_dod_team.h" #include "c_dod_player.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" extern ConVar cl_deathicon_width; extern ConVar cl_deathicon_height; //DECLARE_HUDELEMENT( CDODDeathStatsPanel ); //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- CDODDeathStatsPanel::CDODDeathStatsPanel( const char *pElementName ) : EditablePanel( NULL, "DeathStats" ), CHudElement( pElementName ) { vgui::Panel *pParent = g_pClientMode->GetViewport(); SetParent( pParent ); SetVisible( false ); SetAlpha( 0 ); SetScheme( "ClientScheme" ); m_pAttackerHistoryLabel = new vgui::Label( this, "AttackerDmgLabel", "..." ); m_pSummaryLabel = new vgui::Label( this, "LifeSummaryLabel", "..." ); memset( &m_DeathRecord, 0, sizeof(m_DeathRecord) ); LoadControlSettings("Resource/UI/DeathStats.res"); } void CDODDeathStatsPanel::OnScreenSizeChanged( int iOldWide, int iOldTall ) { LoadControlSettings( "resource/UI/DeathStats.res" ); } void CDODDeathStatsPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); SetBgColor( GetSchemeColor("TransparentLightBlack", pScheme) ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CDODDeathStatsPanel::Reset() { Hide(); } void CDODDeathStatsPanel::Init() { Hide(); ListenForGameEvent( "player_death" ); m_iMaterialTexture = vgui::surface()->CreateNewTextureID(); CHudElement::Init(); } void CDODDeathStatsPanel::VidInit( void ) { m_iconD_skull = gHUD.GetIcon( "d_skull_dod" ); m_pIconKill = gHUD.GetIcon( "stats_kill" ); m_pIconWounded = gHUD.GetIcon( "stats_wounded" ); m_pIconCap = gHUD.GetIcon( "stats_cap" ); m_pIconDefended = gHUD.GetIcon( "stats_defended" ); } //----------------------------------------------------------------------------- // Purpose: Handle player_death message //----------------------------------------------------------------------------- void CDODDeathStatsPanel::FireGameEvent( IGameEvent * event) { if ( Q_strcmp( "player_death", event->GetName() ) == 0 ) { C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); if ( !pLocalPlayer ) return; if ( !g_PR ) return; int victim = engine->GetPlayerForUserID( event->GetInt("userid") ); // only deal with deathnotices where we die if ( victim != pLocalPlayer->entindex() ) { return; } int killer = engine->GetPlayerForUserID( event->GetInt("attacker") ); const char *killedwith = event->GetString( "weapon" ); char fullkilledwith[128]; if ( killedwith && *killedwith ) { Q_snprintf( fullkilledwith, sizeof(fullkilledwith), "d_%s", killedwith ); } else { fullkilledwith[0] = 0; } // Get the names of the players const char *killer_name = g_PR->GetPlayerName( killer ); const char *victim_name = g_PR->GetPlayerName( victim ); if ( !killer_name ) killer_name = ""; if ( !victim_name ) victim_name = ""; m_DeathRecord.Killer.iEntIndex = killer; m_DeathRecord.Victim.iEntIndex = victim; Q_strncpy( m_DeathRecord.Killer.szName, killer_name, MAX_PLAYER_NAME_LENGTH ); Q_strncpy( m_DeathRecord.Victim.szName, victim_name, MAX_PLAYER_NAME_LENGTH ); m_DeathRecord.bSuicide = ( !killer || killer == victim ); // Try and find the death identifier in the icon list m_DeathRecord.iconDeath = gHUD.GetIcon( fullkilledwith ); if ( !m_DeathRecord.iconDeath ) { // Can't find it, so use the default skull & crossbones icon m_DeathRecord.iconDeath = m_iconD_skull; } // Info we get from this message: // - who killed us with what // Info that is networked to the local player // - the hitgroups we hit the guy who killed us with // - life kills // - life woundings // - life caps // - life defenses Show(); } } const char *szHitgroupNames[] = { "head", "chest", "arm", "leg" }; void CDODDeathStatsPanel::Paint( void ) { int deathNoticeWidth = 0; if ( m_DeathRecord.Victim.iEntIndex > 0 ) deathNoticeWidth = DrawDeathNoticeItem( m_iDeathNoticeX, m_iDeathNoticeY ); const int minWidth = XRES(160); int panelWidth = ( deathNoticeWidth < minWidth ? minWidth : deathNoticeWidth ); int wide, tall; // set width of summary label to death notice width m_pSummaryLabel->GetSize( wide, tall ); m_pSummaryLabel->SetSize( panelWidth, tall ); C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer(); if ( !pLocalPlayer ) return; char buf[512]; buf[0] = '\0'; if ( !m_DeathRecord.bSuicide ) { bool bStart = true; bool bHit = false; for ( int i=0;i<4;i++ ) { if ( pLocalPlayer->m_iHitsOnAttacker[i] > 0 ) { bHit = true; if ( bStart ) { Q_snprintf( buf, sizeof(buf), "You hit %s %i %s in the %s\n", m_DeathRecord.Killer.szName, pLocalPlayer->m_iHitsOnAttacker[i], pLocalPlayer->m_iHitsOnAttacker[i] == 1 ? "time" : "times", szHitgroupNames[i] ); bStart = false; } else { Q_snprintf( buf, sizeof(buf), "%s and %i %s in the %s\n", buf, pLocalPlayer->m_iHitsOnAttacker[i], pLocalPlayer->m_iHitsOnAttacker[i] == 1 ? "time" : "times", szHitgroupNames[i] ); } } } } Q_strncat( buf, "\n", sizeof(buf), COPY_ALL_CHARACTERS ); if ( pLocalPlayer->m_iPerLifeKills ) { Q_snprintf( buf, sizeof(buf), "%sKills: %i\n\n", buf, pLocalPlayer->m_iPerLifeKills ); } if ( pLocalPlayer->m_iPerLifeWounded ) { Q_snprintf( buf, sizeof(buf), "%sWounded: %i\n\n", buf, pLocalPlayer->m_iPerLifeWounded ); } if ( pLocalPlayer->m_iPerLifeCaptures ) { Q_snprintf( buf, sizeof(buf), "%sFlag Captures: %i\n\n", buf, pLocalPlayer->m_iPerLifeCaptures ); } if ( pLocalPlayer->m_iPerLifeDefenses ) { Q_snprintf( buf, sizeof(buf), "%sFlag Defenses: %i\n\n", buf, pLocalPlayer->m_iPerLifeDefenses ); } m_pAttackerHistoryLabel->SetText( buf ); m_pAttackerHistoryLabel->SizeToContents(); int panel_h = YRES(160); SetSize( panelWidth, panel_h ); } float GetScale( int nIconWidth, int nIconHeight, int nWidth, int nHeight ); int CDODDeathStatsPanel::DrawDeathNoticeItem( int x, int y ) { // Get the team numbers for the players involved int iKillerTeam = TEAM_UNASSIGNED; int iVictimTeam = TEAM_UNASSIGNED; if( g_PR ) { iKillerTeam = g_PR->GetTeam( m_DeathRecord.Killer.iEntIndex ); iVictimTeam = g_PR->GetTeam( m_DeathRecord.Victim.iEntIndex ); } wchar_t victim[ 256 ]; wchar_t killer[ 256 ]; g_pVGuiLocalize->ConvertANSIToUnicode( m_DeathRecord.Victim.szName, victim, sizeof( victim ) ); g_pVGuiLocalize->ConvertANSIToUnicode( m_DeathRecord.Killer.szName, killer, sizeof( killer ) ); // Get the local position for this notice int len = UTIL_ComputeStringWidth( m_hTextFont, victim ); int iconWide; int iconTall; CHudTexture *icon = m_DeathRecord.iconDeath; Assert( icon ); if ( !icon ) return 0; if( icon->bRenderUsingFont ) { iconWide = surface()->GetCharacterWidth( icon->hFont, icon->cCharacterInFont ); iconTall = surface()->GetFontTall( icon->hFont ); } else { float scale = GetScale( icon->Width(), icon->Height(), XRES(cl_deathicon_width.GetInt()), YRES(cl_deathicon_height.GetInt()) ); iconWide = (int)( scale * (float)icon->Width() ); iconTall = (int)( scale * (float)icon->Height() ); } int spacerX = XRES(5); //int x = xRight - len - spacerX - iconWide - XRES(10); surface()->DrawSetTextFont( m_hTextFont ); int iFontTall = vgui::surface()->GetFontTall( m_hTextFont ); int yText = y + ( iconTall - iFontTall ) / 2; int boxWidth = len + iconWide + spacerX; int boxHeight = MIN( iconTall, m_flLineHeight ); int boxBorder = XRES(2); // Only draw killers name if it wasn't a suicide if ( !m_DeathRecord.bSuicide ) { int nameWidth = UTIL_ComputeStringWidth( m_hTextFont, killer ) + spacerX; // gap //x -= nameWidth; boxWidth += nameWidth; Panel::DrawBox( x-boxBorder, y-boxBorder, boxWidth+2*boxBorder, boxHeight+2*boxBorder, m_ActiveBackgroundColor, 1.0 ); Color c = g_PR->GetTeamColor( iKillerTeam ); surface()->DrawSetTextColor( c ); // Draw killer's name surface()->DrawSetTextPos( x, yText ); const wchar_t *p = killer; while ( *p ) { surface()->DrawUnicodeChar( *p++ ); } surface()->DrawGetTextPos( x, yText ); x += spacerX; } else { Panel::DrawBox( x-boxBorder, y-boxBorder, boxWidth+2*boxBorder, boxHeight+2*boxBorder, m_ActiveBackgroundColor, 1.0 ); } Color iconColor( 255, 80, 0, 255 ); // Draw death weapon //If we're using a font char, this will ignore iconTall and iconWide icon->DrawSelf( x, y, iconWide, iconTall, iconColor ); x += iconWide + spacerX; Color c = g_PR->GetTeamColor( iVictimTeam ); surface()->DrawSetTextColor( c ); // Draw victims name surface()->DrawSetTextFont( m_hTextFont ); //reset the font, draw icon can change it surface()->DrawSetTextPos( x, yText ); const wchar_t *p = victim; while ( *p ) { surface()->DrawUnicodeChar( *p++ ); } return boxWidth; }