diff options
Diffstat (limited to 'game/client/dod/dod_hud_deathnotice.cpp')
| -rw-r--r-- | game/client/dod/dod_hud_deathnotice.cpp | 942 |
1 files changed, 942 insertions, 0 deletions
diff --git a/game/client/dod/dod_hud_deathnotice.cpp b/game/client/dod/dod_hud_deathnotice.cpp new file mode 100644 index 0000000..c00be07 --- /dev/null +++ b/game/client/dod/dod_hud_deathnotice.cpp @@ -0,0 +1,942 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Draws DoD:S's death notices +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "hudelement.h" +#include "hud_macros.h" +#include "c_playerresource.h" +#include "iclientmode.h" +#include <vgui_controls/Controls.h> +#include <vgui_controls/Panel.h> +#include <vgui/ISurface.h> +#include <vgui/ILocalize.h> +#include <KeyValues.h> +#include "c_baseplayer.h" +#include "c_team.h" + +#include "dod_shareddefs.h" +#include "clientmode_dod.h" +#include "c_dod_player.h" +#include "c_dod_playerresource.h" +#include "c_dod_objective_resource.h" +#include "dod_hud_freezepanel.h" +#include "engine/IEngineSound.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +ConVar hud_deathnotice_time( "hud_deathnotice_time", "6", 0 ); +ConVar cl_deathicon_width( "cl_deathicon_width", "57" ); +ConVar cl_deathicon_height( "cl_deathicon_height", "18" ); + +#define MAX_DEATHNOTICE_NAME_LENGTH 128 // to hold multiple player cappers + +// a very useful function for getting the ideal scale factor of a sprite that's to be +// scaled into a space +float GetScale( int nIconWidth, int nIconHeight, int nWidth, int nHeight ); + +// Player entries in a death notice +struct DeathNoticePlayer +{ + char szName[MAX_DEATHNOTICE_NAME_LENGTH]; + int iEntIndex; +}; + +// Contents of each entry in our list of death notices +struct DeathNoticeItem +{ + DeathNoticeItem() + { + iconDeath = NULL; + bSuicide = false; + bCapMsg = false; + bLocalPlayerInvolved = false; + bDefense = false; + bDominating = false; + } + + DeathNoticePlayer Killer; + DeathNoticePlayer Victim; + CHudTexture *iconDeath; + bool bSuicide; + float flDisplayTime; + + // When I see a boolean like this, I know serious bullshit is afoot! + bool bCapMsg; // if this is set, this is a flag cap msg. + // Killer.szName is the list of players that capped + // Victim.szName is the localized point name + // iMaterial is the material index of the flag icon to show + // iEntIndex in Killer is the capping team + + + int iMaterial; + + bool bLocalPlayerInvolved; // Is the local player a capper, killer or victim in this message + + bool bDefense; + + bool bDominating; + wchar_t wzInfoText[32]; // any additional text to display next to icon + +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CHudDeathNotice : public CHudElement, public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CHudDeathNotice, vgui::Panel ); +public: + CHudDeathNotice( const char *pElementName ); + + void Init( void ); + void VidInit( void ); + virtual bool ShouldDraw( void ); + virtual void Paint( void ); + virtual void ApplySchemeSettings( vgui::IScheme *scheme ); + + void SetColorForNoticePlayer( int iTeamNumber ); + void RetireExpiredDeathNotices( void ); + + void FireGameEvent( IGameEvent * event); + + void DrawBackgroundBox( int x, int y, int w, int h, bool bLocalPlayerInvolved ); + + int DrawDefenseItem( DeathNoticeItem *pItem, int xRight, int y ); + int DrawDeathNoticeItem( DeathNoticeItem *pItem, int x, int y ); + int DrawDominationNoticeItem( DeathNoticeItem *pItem, int xRight, int y ); + + virtual bool IsVisible( void ); + + void AddAdditionalMsg( int iKillerID, int iVictimID, const char *pMsgKey ); + + void PlayRivalrySounds( int iKillerIndex, int iVictimIndex, int iType ); + +private: + + CPanelAnimationVarAliasType( float, m_flLineHeight, "LineHeight", "15", "proportional_float" ); + + CPanelAnimationVar( float, m_flMaxDeathNotices, "MaxDeathNotices", "4" ); + + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "HudNumbersTimer" ); + + CPanelAnimationVar( Color, m_BackgroundColor, "BackgroundColor", "255 255 255 100" ); + CPanelAnimationVar( Color, m_ActiveBackgroundColor, "ActiveBackgroundColor", "255 255 255 140" ); + + // Special death notice icons + CHudTexture *m_iconD_skull; + CHudTexture *m_pIconDefended; + CHudTexture *m_iconDomination; + + CUtlVector<DeathNoticeItem> m_DeathNotices; + + int m_iMaterialTexture; +}; + +using namespace vgui; + +DECLARE_HUDELEMENT( CHudDeathNotice ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHudDeathNotice::CHudDeathNotice( const char *pElementName ) : + CHudElement( pElementName ), BaseClass( NULL, "HudDeathNotice" ) +{ + vgui::Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + m_iconD_skull = NULL; + m_iconDomination = NULL; + + SetHiddenBits( HIDEHUD_MISCSTATUS ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDeathNotice::ApplySchemeSettings( IScheme *scheme ) +{ + BaseClass::ApplySchemeSettings( scheme ); + SetPaintBackgroundEnabled( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDeathNotice::Init( void ) +{ + ListenForGameEvent( "player_death" ); + ListenForGameEvent( "dod_point_captured" ); + ListenForGameEvent( "dod_capture_blocked" ); + + m_iMaterialTexture = vgui::surface()->CreateNewTextureID(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDeathNotice::VidInit( void ) +{ + m_iconD_skull = gHUD.GetIcon( "d_skull_dod" ); + m_pIconDefended = gHUD.GetIcon( "icon_defended" ); + m_iconDomination = gHUD.GetIcon( "leaderboard_dominated" ); + m_DeathNotices.Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: Draw if we've got at least one death notice in the queue +//----------------------------------------------------------------------------- +bool CHudDeathNotice::ShouldDraw( void ) +{ + return ( CHudElement::ShouldDraw() && ( m_DeathNotices.Count() ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: Hide if we just took a freezecam screenshot +//----------------------------------------------------------------------------- +bool CHudDeathNotice::IsVisible( void ) +{ + if ( IsTakingAFreezecamScreenshot() ) + return false; + + return BaseClass::IsVisible(); + +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDeathNotice::SetColorForNoticePlayer( int iTeamNumber ) +{ + Color c = g_PR->GetTeamColor( iTeamNumber ); + surface()->DrawSetTextColor( c ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudDeathNotice::Paint() +{ + int yStart = GetClientModeDODNormal()->GetDeathMessageStartHeight(); + + surface()->DrawSetTextFont( m_hTextFont ); + + int y = yStart; + int x = GetWide(); + + int iCount = m_DeathNotices.Count(); + for ( int i = 0; i < iCount; i++ ) + { + if ( m_DeathNotices[i].bDefense ) + y += DrawDefenseItem( &m_DeathNotices[i], x, y ); + else + y += DrawDeathNoticeItem( &m_DeathNotices[i], x, y ); + } + + // Now retire any death notices that have expired + RetireExpiredDeathNotices(); +} + +int CHudDeathNotice::DrawDefenseItem( DeathNoticeItem *pItem, int xRight, int y ) +{ + // Get the team numbers for the players involved + int iKillerTeam = pItem->Killer.iEntIndex; + int iVictimTeam = TEAM_UNASSIGNED; + + wchar_t victim[ 256 ]; + wchar_t killer[ 256 ]; + + g_pVGuiLocalize->ConvertANSIToUnicode( pItem->Victim.szName, victim, sizeof( victim ) ); + g_pVGuiLocalize->ConvertANSIToUnicode( pItem->Killer.szName, killer, sizeof( killer ) ); + + // Get the local position for this notice + int len = UTIL_ComputeStringWidth( m_hTextFont, victim ); + + int iconWide; + int iconTall; + + float scale = ( (float)ScreenHeight() / 480.0f ) * 0.6; //scale based on 800x600 + iconWide = iconTall = (int)( scale * 16.0 ); + + int iconDefSize = (int)( scale * 32.0 ); + + int spacerX = XRES(5); + + int x = xRight - len - spacerX - iconWide - XRES(10); + + x -= iconDefSize; + + surface()->DrawSetTextFont( m_hTextFont ); + int iFontTall = vgui::surface()->GetFontTall( m_hTextFont ); + int yText = y + ( iconDefSize - iFontTall ) / 2; + + int boxWidth = len + iconWide + spacerX; + + boxWidth += iconDefSize; + + int boxHeight = m_flLineHeight; + int boxBorder = XRES(2); + + // Draw Defender's name + int nameWidth = UTIL_ComputeStringWidth( m_hTextFont, killer ) + spacerX; // gap + + x -= nameWidth; + boxWidth += nameWidth; + + DrawBackgroundBox( x-boxBorder, y-boxBorder, boxWidth+2*boxBorder, boxHeight+2*boxBorder, pItem->bLocalPlayerInvolved ); + + SetColorForNoticePlayer( iKillerTeam ); + + // Draw killer's name + surface()->DrawSetTextPos( x, yText ); + surface()->DrawUnicodeString( killer ); + surface()->DrawGetTextPos( x, yText ); + + x += spacerX; + + Color iconColor( 255, 80, 0, 255 ); + + // Draw shield + cap icon + m_pIconDefended->DrawSelf( x, y, iconDefSize, iconDefSize, Color(255,255,255,255) ); + x += iconDefSize + spacerX; + + const char *szMatName = GetMaterialNameFromIndex( pItem->iMaterial ); + + vgui::surface()->DrawSetColor( Color(255,255,255,255) ); + vgui::surface()->DrawSetTextureFile( m_iMaterialTexture, szMatName, true, false); + + int iconY = y + iconDefSize / 2 - iconTall / 2; + vgui::surface()->DrawTexturedRect( x, iconY, x + iconWide, iconY + iconTall ); + x += iconWide; + + SetColorForNoticePlayer( iVictimTeam ); + + // Draw location name + surface()->DrawSetTextFont( m_hTextFont ); //reset the font, draw icon can change it + surface()->DrawSetTextPos( x, yText ); + + surface()->DrawUnicodeString( victim ); + + // return height of this item + // base spacing on the height of the background box + return boxHeight + boxBorder*2 + YRES(4); +} + +// X is right side, do a right align! +int CHudDeathNotice::DrawDeathNoticeItem( DeathNoticeItem *pItem, int xRight, int y ) +{ + if ( pItem->bDominating ) + { + return DrawDominationNoticeItem( pItem, xRight, y ); + } + + bool bCapMsg = pItem->bCapMsg; + + // Get the team numbers for the players involved + int iKillerTeam = TEAM_UNASSIGNED; + int iVictimTeam = TEAM_UNASSIGNED; + + if ( bCapMsg ) + { + iKillerTeam = pItem->Killer.iEntIndex; + iVictimTeam = TEAM_UNASSIGNED; + } + else + { + if( g_PR ) + { + iKillerTeam = g_PR->GetTeam( pItem->Killer.iEntIndex ); + iVictimTeam = g_PR->GetTeam( pItem->Victim.iEntIndex ); + } + } + + wchar_t victim[ 256 ]; + wchar_t killer[ 256 ]; + + g_pVGuiLocalize->ConvertANSIToUnicode( pItem->Victim.szName, victim, sizeof( victim ) ); + g_pVGuiLocalize->ConvertANSIToUnicode( pItem->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 = pItem->iconDeath; + + Assert( icon ); + + if ( bCapMsg ) + { + float scale = ( (float)ScreenHeight() / 480.0f ) * 0.6; //scale based on 800x600 + iconWide = iconTall = (int)( scale * 32.0 ); + } + else + { + 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); + + if ( pItem->bDefense ) + { + x -= iconWide; //m_iDefendedIconSize; + } + + surface()->DrawSetTextFont( m_hTextFont ); + int iFontTall = vgui::surface()->GetFontTall( m_hTextFont ); + int boxWidth = len + iconWide + spacerX; + + if ( pItem->bDefense ) + { + boxWidth += iconWide; //m_iDefendedIconSize; + } + + int boxHeight = m_flLineHeight; //MIN( iconTall, m_flLineHeight ); + int boxBorder = XRES(2); + + int yText = y + ( m_flLineHeight - iFontTall ) / 2; + int yIcon = y + ( m_flLineHeight - iconTall ) / 2; + + // Only draw killers name if it wasn't a suicide + if ( !pItem->bSuicide ) + { + int nameWidth = UTIL_ComputeStringWidth( m_hTextFont, killer ) + spacerX; // gap + + x -= nameWidth; + boxWidth += nameWidth; + + DrawBackgroundBox( x-boxBorder, y-boxBorder, boxWidth+2*boxBorder, boxHeight+2*boxBorder, pItem->bLocalPlayerInvolved ); + + SetColorForNoticePlayer( iKillerTeam ); + + // 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 + { + DrawBackgroundBox( x-boxBorder, y-boxBorder, boxWidth+2*boxBorder, boxHeight+2*boxBorder, pItem->bLocalPlayerInvolved ); + } + + Color iconColor( 255, 80, 0, 255 ); + + // Draw death weapon or cap icon + if ( bCapMsg ) + { + const char *szMatName = GetMaterialNameFromIndex( pItem->iMaterial ); + + vgui::surface()->DrawSetColor( Color(255,255,255,255) ); + vgui::surface()->DrawSetTextureFile( m_iMaterialTexture, szMatName, true, false); + vgui::surface()->DrawTexturedRect( x, yIcon, x + iconWide, yIcon + iconTall ); + x += iconWide + spacerX; + } + else + { + //If we're using a font char, this will ignore iconTall and iconWide + icon->DrawSelf( x, yIcon, iconWide, iconTall, iconColor ); + x += iconWide + spacerX; + } + + SetColorForNoticePlayer( iVictimTeam ); + + // 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 height of this item + // base spacing on the height of the background box + return boxHeight + boxBorder*2 + YRES(4); +} + +int CHudDeathNotice::DrawDominationNoticeItem( DeathNoticeItem *pItem, int xRight, 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( pItem->Killer.iEntIndex ); + iVictimTeam = g_PR->GetTeam( pItem->Victim.iEntIndex ); + } + + wchar_t victim[ 256 ]; + wchar_t killer[ 256 ]; + + g_pVGuiLocalize->ConvertANSIToUnicode( pItem->Victim.szName, victim, sizeof( victim ) ); + g_pVGuiLocalize->ConvertANSIToUnicode( pItem->Killer.szName, killer, sizeof( killer ) ); + + // Get the local position for this notice + int len = UTIL_ComputeStringWidth( m_hTextFont, victim ); + + int iconWide; + int iconTall; + + Assert( pItem->iconDeath ); + + CHudTexture *icon = pItem->iconDeath; + + 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 boxWidth = len + iconWide + spacerX; + + int iDominatingLen = UTIL_ComputeStringWidth( m_hTextFont, pItem->wzInfoText ) + XRES(2); + x -= iDominatingLen; + boxWidth += iDominatingLen; + + int boxHeight = m_flLineHeight; //MIN( iconTall, m_flLineHeight ); + int boxBorder = XRES(2); + + int yText = y + ( m_flLineHeight - iFontTall ) / 2; + int yIcon = y + ( m_flLineHeight - iconTall ) / 2; + + int nameWidth = UTIL_ComputeStringWidth( m_hTextFont, killer ) + spacerX; // gap + + x -= nameWidth; + boxWidth += nameWidth; + + DrawBackgroundBox( x-boxBorder, y-boxBorder, boxWidth+2*boxBorder, boxHeight+2*boxBorder, pItem->bLocalPlayerInvolved ); + + SetColorForNoticePlayer( iKillerTeam ); + + // Draw killer's name + surface()->DrawSetTextPos( x, yText ); + const wchar_t *p = killer; + while ( *p ) + { + surface()->DrawUnicodeChar( *p++ ); + } + surface()->DrawGetTextPos( x, yText ); + + x += spacerX; + + Color iconColor( 255, 80, 0, 255 ); + + //If we're using a font char, this will ignore iconTall and iconWide + icon->DrawSelf( x, yIcon, iconWide, iconTall, iconColor ); + x += iconWide + spacerX; + + surface()->DrawSetTextColor( Color(255,255,255,255) ); + + // Draw dominating string + surface()->DrawSetTextFont( m_hTextFont ); //reset the font, draw icon can change it + surface()->DrawSetTextPos( x, yText ); + p = pItem->wzInfoText; + while ( *p ) + { + surface()->DrawUnicodeChar( *p++ ); + } + x += iDominatingLen; + + SetColorForNoticePlayer( iVictimTeam ); + + // Draw victims name + //surface()->DrawSetTextFont( m_hTextFont ); //reset the font, draw icon can change it + surface()->DrawSetTextPos( x, yText ); + p = victim; + while ( *p ) + { + surface()->DrawUnicodeChar( *p++ ); + } + + // return height of this item + // base spacing on the height of the background box + return boxHeight + boxBorder*2 + YRES(4); +} + +ConVar cl_deathicon_bg_alpha( "cl_deathicon_bg_alpha", "1.0" ); + +void CHudDeathNotice::DrawBackgroundBox( int x, int y, int w, int h, bool bLocalPlayerInvolved ) +{ + Panel::DrawBox( x, y, w, h, + bLocalPlayerInvolved ? m_ActiveBackgroundColor : m_BackgroundColor, + cl_deathicon_bg_alpha.GetFloat() ); +} + +//----------------------------------------------------------------------------- +// Purpose: This message handler may be better off elsewhere +//----------------------------------------------------------------------------- +void CHudDeathNotice::RetireExpiredDeathNotices( void ) +{ + // Loop backwards because we might remove one + int iSize = m_DeathNotices.Size(); + for ( int i = iSize-1; i >= 0; i-- ) + { + if ( m_DeathNotices[i].flDisplayTime < gpGlobals->curtime ) + { + m_DeathNotices.Remove(i); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Server's told us that someone's died +//----------------------------------------------------------------------------- +void CHudDeathNotice::FireGameEvent( IGameEvent * event) +{ + if (!g_PR) + return; + + if ( hud_deathnotice_time.GetFloat() == 0 ) + return; + + C_DODPlayer *pLocal = C_DODPlayer::GetLocalDODPlayer(); + + Assert( pLocal ); + + if ( !pLocal ) + return; + + int iLocalPlayerIndex = pLocal->entindex(); + + const char *pEventName = event->GetName(); + + if ( Q_strcmp( "dod_point_captured", pEventName ) == 0 ) + { + // Cap point index + int cp = event->GetInt( "cp", -1 ); + Assert( cp >= 0 ); + + // Cap point name ( MATTTODO: can't we find this from the point index ? ) + const char *pName = event->GetString( "cpname", "Unnamed Control Point" ); + const wchar_t *pBuf = g_pVGuiLocalize->Find( pName ); + + // Array of capper indeces + const char *cappers = event->GetString("cappers"); + + DeathNoticeItem capMsg; + capMsg.bCapMsg = true; + capMsg.bSuicide = false; + capMsg.bDefense = false; + capMsg.flDisplayTime = gpGlobals->curtime + hud_deathnotice_time.GetFloat(); + capMsg.bLocalPlayerInvolved = false; + + char szCappers[256]; + szCappers[0] = '\0'; + + int len = Q_strlen(cappers); + for( int i=0;i<len;i++ ) + { + int iPlayerIndex = (int)cappers[i]; + + if ( iPlayerIndex == iLocalPlayerIndex ) + capMsg.bLocalPlayerInvolved = true; + + Assert( iPlayerIndex > 0 && iPlayerIndex <= gpGlobals->maxClients ); + + const char *pPlayerName = g_PR->GetPlayerName( iPlayerIndex ); + + if ( i == 0 ) + { + // use first player as the team + capMsg.Killer.iEntIndex = g_PR->GetTeam( iPlayerIndex ); + capMsg.iMaterial = g_pObjectiveResource->GetIconForTeam( cp, capMsg.Killer.iEntIndex ); + + if ( g_pObjectiveResource->GetBombsRequired( cp ) > 0 ) + { + capMsg.iMaterial = g_pObjectiveResource->GetCPBombedIcon( cp ); + } + } + else + { + Q_strncat( szCappers, ", ", sizeof(szCappers), 2 ); + } + + Q_strncat( szCappers, pPlayerName, sizeof(szCappers), COPY_ALL_CHARACTERS ); + } + + Q_strncpy( capMsg.Killer.szName, szCappers, sizeof(capMsg.Killer.szName) ); + + if ( pBuf ) + { + g_pVGuiLocalize->ConvertUnicodeToANSI( pBuf, capMsg.Victim.szName, sizeof(capMsg.Victim.szName) ); + } + else + { + Q_strncpy( capMsg.Victim.szName, pName, sizeof(capMsg.Victim.szName) ); + } + + // Do we have too many death messages in the queue? + if ( m_DeathNotices.Count() > 0 && + m_DeathNotices.Count() >= (int)m_flMaxDeathNotices ) + { + // Remove the oldest one in the queue, which will always be the first + m_DeathNotices.Remove(0); + } + + m_DeathNotices.AddToTail( capMsg ); + + // print a log message + + char szLogMsg[512]; + + Q_snprintf( szLogMsg, sizeof( szLogMsg ), "%s captured %s for the %s\n", + capMsg.Killer.szName, + capMsg.Victim.szName, + capMsg.Killer.iEntIndex == TEAM_ALLIES ? "U.S. Army" : "Wermacht" ); + + Msg( "%s",szLogMsg ); + } + else if ( Q_strcmp( "dod_capture_blocked", pEventName ) == 0 ) + { + // Cap point index + int cp = event->GetInt( "cp", -1 ); + Assert( cp >= 0 ); + + // Cap point name + const char *pName = event->GetString( "cpname", "Unnamed Control Point" ); + const wchar_t *pBuf = g_pVGuiLocalize->Find( pName ); + + // A single blocker entindex + int iBlocker = event->GetInt("blocker"); + + DeathNoticeItem capMsg; + capMsg.bCapMsg = true; + capMsg.bSuicide = false; + capMsg.bDefense = true; + capMsg.flDisplayTime = gpGlobals->curtime + hud_deathnotice_time.GetFloat(); + capMsg.bLocalPlayerInvolved = false; + + capMsg.Killer.iEntIndex = g_PR->GetTeam( iBlocker ); + capMsg.iMaterial = g_pObjectiveResource->GetIconForTeam( cp, capMsg.Killer.iEntIndex ); + + if ( iBlocker == iLocalPlayerIndex ) + capMsg.bLocalPlayerInvolved = true; + + Q_strncpy( capMsg.Killer.szName, g_PR->GetPlayerName( iBlocker ), sizeof(capMsg.Killer.szName) ); + + char buf[128]; + + if ( pBuf ) + { + g_pVGuiLocalize->ConvertUnicodeToANSI( pBuf, buf, sizeof(buf) ); + pName = buf; + } + + Q_snprintf( capMsg.Victim.szName, sizeof(capMsg.Victim.szName), " - %s", pName ); + + // Do we have too many death messages in the queue? + if ( m_DeathNotices.Count() > 0 && + m_DeathNotices.Count() >= (int)m_flMaxDeathNotices ) + { + // Remove the oldest one in the queue, which will always be the first + m_DeathNotices.Remove(0); + } + + m_DeathNotices.AddToTail( capMsg ); + } + else if ( Q_strcmp( "player_death", pEventName ) == 0 ) + { + int killer = engine->GetPlayerForUserID( event->GetInt("attacker") ); + int victim = engine->GetPlayerForUserID( event->GetInt("userid") ); + const char *killedwith = event->GetString( "weapon" ); + + char fullkilledwith[128]; + if ( killedwith && *killedwith ) + { + Q_snprintf( fullkilledwith, sizeof(fullkilledwith), "d_%s", killedwith ); + } + else + { + fullkilledwith[0] = 0; + } + + // Do we have too many death messages in the queue? + if ( m_DeathNotices.Count() > 0 && + m_DeathNotices.Count() >= (int)m_flMaxDeathNotices ) + { + // Remove the oldest one in the queue, which will always be the first + m_DeathNotices.Remove(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 = ""; + + // Make a new death notice + DeathNoticeItem deathMsg; + deathMsg.Killer.iEntIndex = killer; + deathMsg.Victim.iEntIndex = victim; + Q_strncpy( deathMsg.Killer.szName, killer_name, MAX_PLAYER_NAME_LENGTH ); + Q_strncpy( deathMsg.Victim.szName, victim_name, MAX_PLAYER_NAME_LENGTH ); + deathMsg.flDisplayTime = gpGlobals->curtime + hud_deathnotice_time.GetFloat(); + deathMsg.bSuicide = ( !killer || killer == victim ); + deathMsg.bCapMsg = false; + deathMsg.bDefense = false; + deathMsg.iMaterial = -1; + deathMsg.bLocalPlayerInvolved = ( killer == iLocalPlayerIndex || victim == iLocalPlayerIndex ); + + // Try and find the death identifier in the icon list + deathMsg.iconDeath = gHUD.GetIcon( fullkilledwith ); + + if ( !deathMsg.iconDeath ) + { + // Can't find it, so use the default skull & crossbones icon + deathMsg.iconDeath = m_iconD_skull; + } + + // Add it to our list of death notices + m_DeathNotices.AddToTail( deathMsg ); + + if ( event->GetInt( "dominated" ) > 0 ) + { + AddAdditionalMsg( killer, victim, "#Msg_Dominating" ); + PlayRivalrySounds( killer, victim, DOD_DEATHFLAG_DOMINATION ); + } + if ( event->GetInt( "revenge" ) > 0 ) + { + AddAdditionalMsg( killer, victim, "#Msg_Revenge" ); + PlayRivalrySounds( killer, victim, DOD_DEATHFLAG_REVENGE ); + } + + char sDeathMsg[512]; + + // Record the death notice in the console + if ( deathMsg.bSuicide ) + { + if ( !strcmp( fullkilledwith, "d_worldspawn" ) ) + { + Q_snprintf( sDeathMsg, sizeof( sDeathMsg ), "%s died.\n", deathMsg.Victim.szName ); + } + else //d_world + { + Q_snprintf( sDeathMsg, sizeof( sDeathMsg ), "%s suicided.\n", deathMsg.Victim.szName ); + } + } + else + { + Q_snprintf( sDeathMsg, sizeof( sDeathMsg ), "%s killed %s", deathMsg.Killer.szName, deathMsg.Victim.szName ); + + if ( fullkilledwith && *fullkilledwith && (*fullkilledwith > 13 ) ) + { + Q_strncat( sDeathMsg, VarArgs( " with %s.\n", fullkilledwith+2 ), sizeof( sDeathMsg ), COPY_ALL_CHARACTERS ); + } + } + + Msg( "%s",sDeathMsg ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Adds an additional death message +//----------------------------------------------------------------------------- +void CHudDeathNotice::AddAdditionalMsg( int iKillerID, int iVictimID, const char *pMsgKey ) +{ + int iMsg = m_DeathNotices.AddToTail(); + DeathNoticeItem &msg = m_DeathNotices[iMsg]; + + msg.Killer.iEntIndex = iKillerID; + msg.Victim.iEntIndex = iVictimID; + Q_strncpy( msg.Killer.szName, g_PR->GetPlayerName( iKillerID ), ARRAYSIZE( msg.Killer.szName ) ); + Q_strncpy( msg.Victim.szName, g_PR->GetPlayerName( iVictimID ), ARRAYSIZE( msg.Victim.szName ) ); + msg.flDisplayTime = gpGlobals->curtime + hud_deathnotice_time.GetFloat(); + msg.bSuicide = false; + msg.bCapMsg = false; + msg.bDefense = false; + msg.iMaterial = -1; + + msg.bDominating = true; + const wchar_t *wzMsg = g_pVGuiLocalize->Find( pMsgKey ); + if ( wzMsg ) + { + V_wcsncpy( msg.wzInfoText, wzMsg, sizeof( msg.wzInfoText ) ); + } + msg.iconDeath = m_iconDomination; + + int iLocalPlayerIndex = GetLocalPlayerIndex(); + if ( iLocalPlayerIndex == iVictimID || iLocalPlayerIndex == iKillerID ) + { + msg.bLocalPlayerInvolved = true; + } +} + +ConVar dod_playrivalrysounds( "dod_playrivalrysounds", "1", FCVAR_ARCHIVE ); + +void CHudDeathNotice::PlayRivalrySounds( int iKillerIndex, int iVictimIndex, int iType ) +{ + if ( dod_playrivalrysounds.GetBool() == false ) + return; + + int iLocalPlayerIndex = GetLocalPlayerIndex(); + + //We're not involved in this kill + if ( iKillerIndex != iLocalPlayerIndex && iVictimIndex != iLocalPlayerIndex ) + return; + + const char *pszSoundName = NULL; + + if ( iType == DOD_DEATHFLAG_DOMINATION ) + { + if ( iKillerIndex == iLocalPlayerIndex ) + { + pszSoundName = "Game.Domination"; + } + else if ( iVictimIndex == iLocalPlayerIndex ) + { + pszSoundName = "Game.Nemesis"; + } + } + else if ( iType == DOD_DEATHFLAG_REVENGE ) + { + pszSoundName = "Game.Revenge"; + } + + CLocalPlayerFilter filter; + C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, pszSoundName ); +}
\ No newline at end of file |