summaryrefslogtreecommitdiff
path: root/game/client/tf/tf_hud_deathnotice.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/tf/tf_hud_deathnotice.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/client/tf/tf_hud_deathnotice.cpp')
-rw-r--r--game/client/tf/tf_hud_deathnotice.cpp1635
1 files changed, 1635 insertions, 0 deletions
diff --git a/game/client/tf/tf_hud_deathnotice.cpp b/game/client/tf/tf_hud_deathnotice.cpp
new file mode 100644
index 0000000..44485c6
--- /dev/null
+++ b/game/client/tf/tf_hud_deathnotice.cpp
@@ -0,0 +1,1635 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Draws CSPort'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 "vgui_controls/TextImage.h"
+#include <KeyValues.h>
+#include "c_baseplayer.h"
+#include "c_team.h"
+#include "gcsdk/gcclientsdk.h"
+#include "tf_gcmessages.h"
+#include "tf_item_inventory.h"
+
+#include "hud_basedeathnotice.h"
+
+#include "tf_shareddefs.h"
+#include "clientmode_tf.h"
+#include "c_tf_player.h"
+#include "c_tf_playerresource.h"
+#include "tf_hud_freezepanel.h"
+#include "engine/IEngineSound.h"
+#include "tf_controls.h"
+#include "tf_gamerules.h"
+#include "econ_notifications.h"
+//#include "econ/econ_controls.h"
+#include "passtime_game_events.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+using namespace vgui;
+
+// Must match resource/tf_objects.txt!!!
+const char *szLocalizedObjectNames[OBJ_LAST] =
+{
+ "#TF_Object_Dispenser",
+ "#TF_Object_Tele",
+ "#TF_Object_Sentry",
+ "#TF_object_Sapper"
+};
+
+ConVar cl_hud_killstreak_display_time( "cl_hud_killstreak_display_time", "3", FCVAR_ARCHIVE, "How long a killstreak notice stays on the screen (in seconds). Range is from 0 to 100." );
+ConVar cl_hud_killstreak_display_fontsize( "cl_hud_killstreak_display_fontsize", "0", FCVAR_ARCHIVE, "Adjusts font size of killstreak notices. Range is from 0 to 2 (default is 1)." );
+ConVar cl_hud_killstreak_display_alpha( "cl_hud_killstreak_display_alpha", "120", FCVAR_ARCHIVE, "Adjusts font alpha value of killstreak notices. Range is from 0 to 255 (default is 200)." );
+
+const int STREAK_MIN = 5;
+const int STREAK_MIN_MVM = 20;
+const int STREAK_MIN_DUCKS = 10;
+
+static int MinStreakForType( CTFPlayerShared::ETFStreak eStreakType )
+{
+ bool bIsMvM = TFGameRules() && TFGameRules()->IsMannVsMachineMode();
+ if ( eStreakType == CTFPlayerShared::kTFStreak_Ducks )
+ {
+ return STREAK_MIN_DUCKS;
+ }
+ if ( eStreakType == CTFPlayerShared::kTFStreak_Duck_levelup )
+ {
+ return 1;
+ }
+ if ( bIsMvM )
+ {
+ return STREAK_MIN_MVM;
+ }
+ return STREAK_MIN;
+}
+
+//=========================================================
+// CTFStreakNotice
+//=========================================================
+class CTFStreakNotice : public CHudElement, public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CTFStreakNotice, vgui::EditablePanel );
+public:
+ CTFStreakNotice( const char *pName );
+
+ virtual bool ShouldDraw( void ) OVERRIDE;
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme ) OVERRIDE;
+ virtual void Paint( void ) OVERRIDE;
+
+ void StreakEnded( CTFPlayerShared::ETFStreak eStreakType, int iKillerID, int iVictimID, int iStreak );
+ void StreakUpdated( CTFPlayerShared::ETFStreak eStreakType, int iPlayerID, int iStreak, int iStreakIncrement );
+
+ bool IsCurrentStreakHigherPriority( CTFPlayerShared::ETFStreak eStreakType, int iStreak );
+ HFont GetStreakFont( void );
+
+private:
+ CExLabel *m_pLabel;
+ EditablePanel *m_pBackground;
+
+ float m_flLastMessageTime;
+ int m_nCurrStreakCount;
+ CTFPlayerShared::ETFStreak m_nCurrStreakType;
+
+ int m_nLabelXPos;
+ int m_nLabelYPos;
+
+ CHudTexture *m_iconKillStreak;
+ CHudTexture *m_iconDuckStreak;
+};
+
+//-----------------------------------------------------------------------------
+CTFStreakNotice::CTFStreakNotice( const char *pName ) : CHudElement( pName ), vgui::EditablePanel( NULL, pName )
+{
+ SetParent( g_pClientMode->GetViewport() );
+
+ m_pBackground = new EditablePanel( this, "Background" );
+ m_pLabel = new CExLabel( this, "SplashLabel", "" );
+
+ m_flLastMessageTime = -10.0f;
+ m_nCurrStreakCount = 0;
+ m_nCurrStreakType = (CTFPlayerShared::ETFStreak)0;
+
+ m_iconKillStreak = gHUD.GetIcon( "leaderboard_streak" );
+ m_iconDuckStreak = gHUD.GetIcon( "eotl_duck" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CTFStreakNotice::ShouldDraw( void )
+{
+ if ( !CHudElement::ShouldDraw() )
+ return false;
+
+ C_TFPlayer *pPlayer = CTFPlayer::GetLocalTFPlayer();
+ if ( !pPlayer )
+ return false;
+
+ if ( IsTakingAFreezecamScreenshot() )
+ return false;
+
+ return m_nCurrStreakCount > 0;
+}
+
+//-----------------------------------------------------------------------------
+void CTFStreakNotice::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ LoadControlSettings( "resource/UI/HudKillStreakNotice.res" );
+
+ m_pLabel->GetPos( m_nLabelXPos, m_nLabelYPos );
+
+ SetSize( XRES(640), YRES(480) );
+}
+
+//-----------------------------------------------------------------------------
+void CTFStreakNotice::Paint( void )
+{
+ int nDisplayTime = clamp( cl_hud_killstreak_display_time.GetInt(), 1, 100 );
+ if ( m_flLastMessageTime + nDisplayTime < gpGlobals->realtime )
+ {
+ SetVisible( false );
+ m_nCurrStreakCount = 0;
+ return;
+ }
+
+ float flFadeTime = 1.5f;
+ float flTimeRemaining = (float)nDisplayTime - ( gpGlobals->realtime - m_flLastMessageTime );
+
+ SetVisible( true );
+ if ( flTimeRemaining > flFadeTime )
+ {
+ SetAlpha( 255 );
+ }
+ else
+ {
+ float flAlpha = RemapValClamped( flTimeRemaining, flFadeTime, 0.f, 255.f, 0.f );
+ SetAlpha( flAlpha );
+ }
+
+ // Move labels down when in spectator
+ C_TFPlayer *pPlayer = CTFPlayer::GetLocalTFPlayer();
+ CHudTexture *pIcon = ( m_nCurrStreakType == CTFPlayerShared::kTFStreak_Ducks || m_nCurrStreakType == CTFPlayerShared::kTFStreak_Duck_levelup ) ? m_iconDuckStreak : m_iconKillStreak;
+ if ( pPlayer && pIcon )
+ {
+ int nYOffset = ( pPlayer->GetObserverMode() > OBS_MODE_FREEZECAM ? YRES(40) : 0 );
+
+ int iWide, iTall;
+ m_pLabel->GetContentSize( iWide, iTall );
+ m_pLabel->SizeToContents();
+ m_pLabel->SetPos( XRES(320) - iWide / 2, m_nLabelYPos + nYOffset );
+
+ m_pBackground->SetSize( iWide + iTall / 2, iTall ); // add in icon width
+ m_pBackground->SetPos( XRES(315) - iWide / 2, m_nLabelYPos + nYOffset);
+
+ wchar_t szTitle[256];
+ m_pLabel->GetText( szTitle, 256 );
+ HFont hFont = GetStreakFont();
+ int iTextWide= UTIL_ComputeStringWidth( hFont, szTitle );
+ pIcon->DrawSelf( XRES(320) - (iWide / 2) + iTextWide, m_nLabelYPos + nYOffset, iTall, iTall, Color(235, 226, 202, GetAlpha() ) );
+ }
+
+ BaseClass::Paint();
+}
+
+//-----------------------------------------------------------------------------
+void CTFStreakNotice::StreakEnded( CTFPlayerShared::ETFStreak eStreakType, int iKillerID, int iVictimID, int iStreak )
+{
+ if ( iStreak < 10 )
+ return;
+
+ if ( IsCurrentStreakHigherPriority( eStreakType, iStreak ) )
+ return;
+
+ // Temp override all messages
+ // Add New message
+ m_flLastMessageTime = gpGlobals->realtime;
+
+ // Generate the String
+ const wchar_t *wzMsg = NULL;
+ bool bSelfKill = false;
+ if ( iKillerID == iVictimID )
+ {
+ wzMsg = g_pVGuiLocalize->Find( ( eStreakType == CTFPlayerShared::kTFStreak_Ducks ) ? "#Msg_DuckStreakEndSelf" : "#Msg_KillStreakEndSelf" );
+ bSelfKill = true;
+ }
+ else
+ {
+ wzMsg = g_pVGuiLocalize->Find( ( eStreakType == CTFPlayerShared::kTFStreak_Ducks ) ? "#Msg_DuckStreakEnd" : "#Msg_KillStreakEnd" );
+ }
+
+ if ( !wzMsg )
+ return;
+
+ // m_nCurrStreakCount = iStreak;
+
+ // Killer Name
+ wchar_t wszKillerName[MAX_PLAYER_NAME_LENGTH / 2];
+ g_pVGuiLocalize->ConvertANSIToUnicode( g_PR->GetPlayerName( iKillerID ), wszKillerName, sizeof(wszKillerName) );
+
+ // Victim Name
+ wchar_t wszVictimName[MAX_PLAYER_NAME_LENGTH / 2];
+ g_pVGuiLocalize->ConvertANSIToUnicode( g_PR->GetPlayerName( iVictimID ), wszVictimName, sizeof(wszVictimName) );
+
+ // Count
+ wchar_t wzCount[10];
+ _snwprintf( wzCount, ARRAYSIZE( wzCount ), L"%d", iStreak );
+
+ wchar_t wTemp[256];
+ if ( bSelfKill )
+ {
+ g_pVGuiLocalize->ConstructString_safe( wTemp, wzMsg, 2, wszKillerName, wzCount );
+ }
+ else
+ {
+ g_pVGuiLocalize->ConstructString_safe( wTemp, wzMsg, 3, wszKillerName, wszVictimName, wzCount );
+ }
+
+ HFont hFont = GetStreakFont();
+ if ( m_pLabel->GetFont() != hFont )
+ {
+ m_pLabel->SetFont( hFont );
+ }
+ m_pLabel->SetText( wTemp );
+
+ // Get player Team for color
+ Color cKillerColor(235, 226, 202, 255);
+ if ( g_PR->GetTeam( iKillerID ) == TF_TEAM_RED )
+ {
+ cKillerColor = COLOR_RED;
+ }
+ else if ( g_PR->GetTeam( iKillerID ) == TF_TEAM_BLUE )
+ {
+ cKillerColor = COLOR_BLUE;
+ }
+
+ Color cVictimColor(235, 226, 202, 255);
+ if ( g_PR->GetTeam( iVictimID ) == TF_TEAM_RED )
+ {
+ cVictimColor = COLOR_RED;
+ }
+ else if ( g_PR->GetTeam( iVictimID ) == TF_TEAM_BLUE )
+ {
+ cVictimColor = COLOR_BLUE;
+ }
+
+ m_pLabel->GetTextImage()->ClearColorChangeStream();
+
+ // We change the title's text color to match the colors of the matching model panel backgrounds
+ wchar_t *txt = wTemp;
+ int iWChars = 0;
+ while ( txt && *txt )
+ {
+ switch ( *txt )
+ {
+ case 0x01: // Normal color
+ m_pLabel->GetTextImage()->AddColorChange( Color(235, 226, 202, cl_hud_killstreak_display_alpha.GetInt() ), iWChars );
+ break;
+ case 0x02: // Team color
+ m_pLabel->GetTextImage()->AddColorChange( Color( cKillerColor.r(), cKillerColor.g(), cKillerColor.b(), cl_hud_killstreak_display_alpha.GetInt() ), iWChars );
+ break;
+ case 0x03: // Item 2 color
+ m_pLabel->GetTextImage()->AddColorChange( Color( cVictimColor.r(), cVictimColor.g(), cVictimColor.b(), cl_hud_killstreak_display_alpha.GetInt() ), iWChars );
+ break;
+ default:
+ break;
+ }
+
+ txt++;
+ iWChars++;
+ }
+
+ m_flLastMessageTime = gpGlobals->realtime;
+ SetVisible( true );
+}
+
+//-----------------------------------------------------------------------------
+void CTFStreakNotice::StreakUpdated( CTFPlayerShared::ETFStreak eStreakType, int iKillerID, int iStreak, int iStreakIncrement )
+{
+ // Temp override all messages
+ // Add New message
+
+ bool bIsMvM = TFGameRules() && TFGameRules()->IsMannVsMachineMode();
+ int iStreakMin = MinStreakForType( eStreakType );
+
+ if ( IsCurrentStreakHigherPriority( eStreakType, iStreak ) )
+ return;
+
+ // Is this message worth responding to
+ int iStreakTier = 0;
+ if ( eStreakType == CTFPlayerShared::kTFStreak_Ducks)
+ {
+ // Notices at 15, 30, then increments of 50. We may increment by multiple ducks per kill, so check if we passed over a milestone.
+ if ( iStreak >= 15 && ( iStreak - iStreakIncrement < 15 ) )
+ {
+ iStreakTier = 1;
+ iStreak = 15;
+ }
+ else if ( iStreak >= 30 && ( iStreak - iStreakIncrement <30 ) )
+ {
+ iStreakTier = 2;
+ iStreak = 30;
+ }
+ else if ( iStreak > 50 && iStreak % 50 < iStreakIncrement )
+ {
+ iStreakTier = Min( 2 + ( iStreak / 50 ), 5 );
+ iStreak -= iStreak % 50;
+ }
+ else
+ {
+ return;
+ }
+ }
+ else if ( eStreakType == CTFPlayerShared::kTFStreak_Duck_levelup )
+ {
+ iStreakTier = 5;
+ }
+ else if ( bIsMvM )
+ {
+ if ( iStreak % iStreakMin != 0 )
+ return;
+
+ iStreakTier = iStreak / iStreakMin;
+ }
+ else
+ {
+ if ( iStreak == 5 )
+ {
+ iStreakTier = 1;
+ }
+ else if ( iStreak == 10 )
+ {
+ iStreakTier = 2;
+ }
+ else if ( iStreak == 15 )
+ {
+ iStreakTier = 3;
+ }
+ else if ( iStreak == 20 )
+ {
+ iStreakTier = 4;
+ }
+ else if ( iStreak % 10 == 0 || iStreak % 10 == 5 )
+ {
+ iStreakTier = 5;
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ m_nCurrStreakCount = iStreak;
+ m_nCurrStreakType = eStreakType;
+
+ const wchar_t *wzMsg = NULL;
+ const char *pszSoundName = "Game.KillStreak";
+ Color cCustomColor(235, 226, 202, 255);
+ if ( eStreakType == CTFPlayerShared::kTFStreak_Ducks )
+ {
+ // Duckstreak tiers
+ switch ( iStreakTier )
+ {
+ case 1:
+ // TODO duckier colors?
+ cCustomColor = Color( 112, 176, 74, 255); // Green
+ wzMsg = g_pVGuiLocalize->Find( "#Msg_DuckStreak1" );
+ //pszSoundName = "Announcer.DuckStreak_Level1";
+ break;
+ case 2:
+ cCustomColor = Color( 207, 106, 50, 255); // Orange
+ wzMsg = g_pVGuiLocalize->Find( "#Msg_DuckStreak2" );
+ //pszSoundName = "Announcer.DuckStreak_Level2";
+ break;
+ case 3:
+ cCustomColor = Color( 134, 80, 172, 255); // Purple
+ wzMsg = g_pVGuiLocalize->Find( "#Msg_DuckStreak3" );
+ //pszSoundName = "Announcer.DuckStreak_Level3";
+ break;
+ case 4:
+ cCustomColor = Color(255, 215, 0, 255); // Gold
+ wzMsg = g_pVGuiLocalize->Find( "#Msg_DuckStreak4" );
+ //pszSoundName = "Announcer.DuckStreak_Level4";
+ break;
+ default:
+ cCustomColor = Color(255, 215, 0, 255); // Still Gold
+ wzMsg = g_pVGuiLocalize->Find( "#Msg_DuckStreak5" );
+ //pszSoundName = "Announcer.DuckStreak_Level4";
+ break;
+ }
+ }
+ else if ( eStreakType == CTFPlayerShared::kTFStreak_Duck_levelup )
+ {
+ cCustomColor = Color( 255, 215, 0, 255 ); // Gold
+ switch ( RandomInt( 1, 3 ) )
+ {
+ case 1: wzMsg = g_pVGuiLocalize->Find( "#Msg_DuckLevelup1" ); break;
+ case 2: wzMsg = g_pVGuiLocalize->Find( "#Msg_DuckLevelup2" ); break;
+ default: wzMsg = g_pVGuiLocalize->Find( "#Msg_DuckLevelup3" ); break;
+ }
+ }
+ else
+ {
+ // Killstreak tiers
+ switch ( iStreakTier )
+ {
+ case 1:
+ cCustomColor = Color( 112, 176, 74, 255); // Green
+ wzMsg = g_pVGuiLocalize->Find( "#Msg_KillStreak1" );
+ //pszSoundName = "Announcer.KillStreak_Level1";
+ break;
+ case 2:
+ cCustomColor = Color( 207, 106, 50, 255); // Orange
+ wzMsg = g_pVGuiLocalize->Find( "#Msg_KillStreak2" );
+ //pszSoundName = "Announcer.KillStreak_Level2";
+ break;
+ case 3:
+ cCustomColor = Color( 134, 80, 172, 255); // Purple
+ wzMsg = g_pVGuiLocalize->Find( "#Msg_KillStreak3" );
+ //pszSoundName = "Announcer.KillStreak_Level3";
+ break;
+ case 4:
+ cCustomColor = Color(255, 215, 0, 255); // Gold
+ wzMsg = g_pVGuiLocalize->Find( "#Msg_KillStreak4" );
+ //pszSoundName = "Announcer.KillStreak_Level4";
+ break;
+ default:
+ cCustomColor = Color(255, 215, 0, 255); // Still Gold
+ wzMsg = g_pVGuiLocalize->Find( "#Msg_KillStreak5" );
+ //pszSoundName = "Announcer.KillStreak_Level4";
+ break;
+ }
+ }
+
+ if ( !wzMsg )
+ return;
+
+ // Get player Team for color
+ Color cTeamColor(235, 226, 202, 255);
+ if ( g_PR->GetTeam( iKillerID ) == TF_TEAM_RED )
+ {
+ cTeamColor = COLOR_RED;
+ }
+ else if ( g_PR->GetTeam( iKillerID ) == TF_TEAM_BLUE )
+ {
+ cTeamColor = COLOR_BLUE;
+ }
+
+ // Generate the String
+ // Count
+ wchar_t wzCount[10];
+ _snwprintf( wzCount, ARRAYSIZE( wzCount ), L"%d", iStreak );
+
+ // Name
+ wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH / 2];
+ g_pVGuiLocalize->ConvertANSIToUnicode( g_PR->GetPlayerName( iKillerID ), wszPlayerName, sizeof(wszPlayerName) );
+
+ wchar_t wTemp[256];
+ g_pVGuiLocalize->ConstructString_safe( wTemp, wzMsg, 2, wszPlayerName, wzCount );
+
+ HFont hFont = GetStreakFont();
+ if ( m_pLabel->GetFont() != hFont )
+ {
+ m_pLabel->SetFont( hFont );
+ }
+ m_pLabel->SetText( wTemp );
+
+ // Now go through the string and find the escape characters telling us where the color changes are
+ m_pLabel->GetTextImage()->ClearColorChangeStream();
+
+ // We change the title's text color to match the colors of the matching model panel backgrounds
+ wchar_t *txt = wTemp;
+ int iWChars = 0;
+ while ( txt && *txt )
+ {
+ switch ( *txt )
+ {
+ case 0x01: // Normal color
+ m_pLabel->GetTextImage()->AddColorChange( Color(235,226,202,cl_hud_killstreak_display_alpha.GetInt() ), iWChars );
+ break;
+ case 0x02: // Team color
+ m_pLabel->GetTextImage()->AddColorChange( Color( cTeamColor.r(), cTeamColor.g(), cTeamColor.b(), cl_hud_killstreak_display_alpha.GetInt() ), iWChars );
+ break;
+ case 0x03: // Item 2 color
+ m_pLabel->GetTextImage()->AddColorChange( Color( cCustomColor.r(), cCustomColor.g(), cCustomColor.b(), cl_hud_killstreak_display_alpha.GetInt() ), iWChars );
+ break;
+ default:
+ break;
+ }
+
+ txt++;
+ iWChars++;
+ }
+
+ // Play Local Sound
+ int iLocalPlayerIndex = GetLocalPlayerIndex();
+ if ( iLocalPlayerIndex == iKillerID && pszSoundName )
+ {
+ CLocalPlayerFilter filter;
+ C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, pszSoundName );
+ }
+
+ m_flLastMessageTime = gpGlobals->realtime + (float)iStreakTier / 2.0;
+ SetVisible( true );
+}
+
+//-----------------------------------------------------------------------------
+bool CTFStreakNotice::IsCurrentStreakHigherPriority( CTFPlayerShared::ETFStreak eStreakType, int iStreak )
+{
+ // duck level ups are highest priority
+ if ( eStreakType == CTFPlayerShared::kTFStreak_Duck_levelup )
+ return false;
+
+ if ( !m_nCurrStreakCount )
+ return false;
+
+ // Ducks never override kills
+ if ( m_nCurrStreakType == CTFPlayerShared::kTFStreak_Kills && eStreakType == CTFPlayerShared::kTFStreak_Ducks )
+ return true;
+
+ // But kills always override ducks
+ if ( m_nCurrStreakType == CTFPlayerShared::kTFStreak_Ducks && eStreakType == CTFPlayerShared::kTFStreak_Kills )
+ return false;
+
+ // Don't stomp a higher streak with a lower, unless it's been around long enough
+ float flElapsedTime = gpGlobals->realtime - m_flLastMessageTime;
+ float flDisplayMinTime = Max( ( cl_hud_killstreak_display_time.GetFloat() / 3.f ), 1.f );
+ return ( iStreak < m_nCurrStreakCount && flElapsedTime < flDisplayMinTime );
+}
+
+//-----------------------------------------------------------------------------
+HFont CTFStreakNotice::GetStreakFont( void )
+{
+ vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
+
+ const char *pszFontName = "HudFontSmallestBold";
+ int nFontSize = cl_hud_killstreak_display_fontsize.GetInt(); // Default is 1: HudFontSmallBold
+ if ( nFontSize == 1 )
+ {
+ pszFontName = "HudFontSmallBold";
+ }
+ else if ( nFontSize == 2 )
+ {
+ pszFontName = "HudFontMediumSmallBold";
+ }
+
+ return pScheme->GetFont( pszFontName, true );
+}
+
+DECLARE_HUDELEMENT( CTFStreakNotice );
+
+
+//-----------------------------------------------------------------------------
+// TFDeathNotice
+//-----------------------------------------------------------------------------
+class CTFHudDeathNotice : public CHudBaseDeathNotice
+{
+ DECLARE_CLASS_SIMPLE( CTFHudDeathNotice, CHudBaseDeathNotice );
+public:
+ CTFHudDeathNotice( const char *pElementName ) : CHudBaseDeathNotice( pElementName ) {};
+ virtual void Init( void );
+ virtual void ApplySchemeSettings( vgui::IScheme *scheme );
+ virtual bool IsVisible( void );
+ virtual bool ShouldDraw( void );
+
+ virtual void FireGameEvent( IGameEvent *event );
+ void PlayRivalrySounds( int iKillerIndex, int iVictimIndex, int iType );
+ virtual bool ShouldShowDeathNotice( IGameEvent *event );
+
+protected:
+ virtual void OnGameEvent( IGameEvent *event, int iDeathNoticeMsg );
+ virtual Color GetTeamColor( int iTeamNumber, bool bLocalPlayerInvolved = false );
+ virtual Color GetInfoTextColor( int iDeathNoticeMsg );
+ virtual Color GetBackgroundColor ( int iDeathNoticeMsg );
+ virtual bool EventIsPlayerDeath( const char *eventName );
+
+ virtual int UseExistingNotice( IGameEvent *event );
+
+private:
+ void AddAdditionalMsg( int iKillerID, int iVictimID, const char *pMsgKey );
+ void AddStreakMsg( CTFPlayerShared::ETFStreak eStreakType, int iKillerID, int iKillerStreak, int iStreakIncrement, int iVictimID, int iDeathNoticeMsg );
+ void AddStreakEndedMsg( CTFPlayerShared::ETFStreak eStreakType, int iKillerID, int iVictimID, int iVictimStreak, int iDeathNoticeMsg );
+
+ CHudTexture* GetMannPowerIcon( RuneTypes_t tRuneType, bool bRedTeam );
+
+ CHudTexture *m_iconDomination;
+ CHudTexture *m_iconKillStreak;
+ CHudTexture *m_iconDuckStreak;
+ CHudTexture *m_iconDuckStreakDNeg;
+ CHudTexture *m_iconKillStreakDNeg;
+
+ CPanelAnimationVar( Color, m_clrBlueText, "TeamBlue", "153 204 255 255" );
+ CPanelAnimationVar( Color, m_clrRedText, "TeamRed", "255 64 64 255" );
+ CPanelAnimationVar( Color, m_clrPurpleText, "PurpleText", "134 80 172 255" );
+ CPanelAnimationVar( Color, m_clrGreenText, "GreenText", "112 176 74 255" );
+ CPanelAnimationVar( Color, m_clrLocalPlayerText, "LocalPlayerColor", "65 65 65 255" );
+
+ CTFStreakNotice *m_pStreakNotice;
+
+ bool m_bShowItemOnKill;
+};
+
+DECLARE_HUDELEMENT( CTFHudDeathNotice );
+
+void CTFHudDeathNotice::Init()
+{
+ BaseClass::Init();
+
+ ListenForGameEvent( "fish_notice" );
+ ListenForGameEvent( "fish_notice__arm" );
+ ListenForGameEvent( "duck_xp_level_up" );
+ //ListenForGameEvent( "throwable_hit" );
+
+ m_bShowItemOnKill = true;
+
+ // PASSTIME if this is called at level load or something we should check mode before this block
+ ListenForGameEvent( PasstimeGameEvents::BallGet::s_eventName );
+ ListenForGameEvent( PasstimeGameEvents::BallStolen::s_eventName );
+ ListenForGameEvent( PasstimeGameEvents::Score::s_eventName );
+ ListenForGameEvent( PasstimeGameEvents::PassCaught::s_eventName );
+ ListenForGameEvent( PasstimeGameEvents::BallBlocked::s_eventName );
+}
+
+void CTFHudDeathNotice::ApplySchemeSettings( vgui::IScheme *scheme )
+{
+ BaseClass::ApplySchemeSettings( scheme );
+
+ m_iconDomination = gHUD.GetIcon( "leaderboard_dominated" );
+
+ m_iconKillStreak = gHUD.GetIcon( "leaderboard_streak" );
+ m_iconKillStreakDNeg = gHUD.GetIcon( "leaderboard_streak_dneg" );
+ m_iconDuckStreak = gHUD.GetIcon( "eotl_duck" );
+ m_iconDuckStreakDNeg = gHUD.GetIcon( "eotl_duck_dneg" );
+ m_pStreakNotice = new CTFStreakNotice( "KillStreakNotice" );
+}
+
+bool CTFHudDeathNotice::IsVisible( void )
+{
+ if ( IsTakingAFreezecamScreenshot() )
+ return false;
+
+ return BaseClass::IsVisible();
+}
+
+bool CTFHudDeathNotice::ShouldDraw( void )
+{
+ return true;
+}
+
+bool CTFHudDeathNotice::ShouldShowDeathNotice( IGameEvent *event )
+{
+ if ( event->GetBool( "silent_kill" ) )
+ {
+ // Don't show a kill event for the team of the silent kill victim.
+ int iVictimID = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
+ C_TFPlayer* pVictim = ToTFPlayer( UTIL_PlayerByIndex( iVictimID ) );
+ if ( pVictim && pVictim->GetTeamNumber() == GetLocalPlayerTeam() && iVictimID != GetLocalPlayerIndex() )
+ {
+ return false;
+ }
+ }
+
+ if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() && ( event->GetInt( "death_flags" ) & TF_DEATH_MINIBOSS ) == 0 )
+ {
+ int iLocalPlayerIndex = GetLocalPlayerIndex();
+
+ if ( iLocalPlayerIndex != engine->GetPlayerForUserID( event->GetInt( "attacker" ) ) &&
+ iLocalPlayerIndex != engine->GetPlayerForUserID( event->GetInt( "assister" ) ) )
+ {
+ C_TFPlayer* pVictim = ToTFPlayer( UTIL_PlayerByIndex( engine->GetPlayerForUserID( event->GetInt( "userid" ) ) ) );
+ if ( pVictim && pVictim->GetTeamNumber() == TF_TEAM_PVE_INVADERS )
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+void CTFHudDeathNotice::PlayRivalrySounds( int iKillerIndex, int iVictimIndex, int iType )
+{
+ int iLocalPlayerIndex = GetLocalPlayerIndex();
+
+ //We're not involved in this kill
+ if ( iKillerIndex != iLocalPlayerIndex && iVictimIndex != iLocalPlayerIndex )
+ return;
+
+ const char *pszSoundName = NULL;
+
+ if ( iType == TF_DEATH_DOMINATION )
+ {
+ if ( iKillerIndex == iLocalPlayerIndex )
+ {
+ pszSoundName = "Game.Domination";
+ }
+ else if ( iVictimIndex == iLocalPlayerIndex )
+ {
+ pszSoundName = "Game.Nemesis";
+ }
+ }
+ else if ( iType == TF_DEATH_REVENGE )
+ {
+ pszSoundName = "Game.Revenge";
+ }
+
+ CLocalPlayerFilter filter;
+ C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, pszSoundName );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Server's told us that someone's died
+//-----------------------------------------------------------------------------
+void CTFHudDeathNotice::FireGameEvent( IGameEvent *event )
+{
+ const char * pszEventName = event->GetName();
+ if ( FStrEq( "duck_xp_level_up", pszEventName ) )
+ {
+ int level = event->GetInt( "level" );
+ AddStreakMsg( CTFPlayerShared::kTFStreak_Duck_levelup, GetLocalPlayerIndex(), level, 1, -1, 0 );
+ return;
+ }
+
+ BaseClass::FireGameEvent( event );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CTFHudDeathNotice::EventIsPlayerDeath( const char* eventName )
+{
+ return FStrEq( eventName, "fish_notice" )
+ || FStrEq( eventName, "fish_notice__arm" )
+ //|| FStrEq( eventName, "throwable_hit" )
+ || BaseClass::EventIsPlayerDeath( eventName );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when a game event happens and a death notice is about to be
+// displayed. This method can examine the event and death notice and
+// make game-specific tweaks to it before it is displayed
+//-----------------------------------------------------------------------------
+void CTFHudDeathNotice::OnGameEvent( IGameEvent *event, int iDeathNoticeMsg )
+{
+ const bool bIsSillyPyroVision = IsLocalPlayerUsingVisionFilterFlags( TF_VISION_FILTER_PYRO );
+
+ const char *pszEventName = event->GetName();
+
+ if ( FStrEq( pszEventName, "player_death" ) || FStrEq( pszEventName, "object_destroyed" ) )
+ {
+ bool bIsObjectDestroyed = FStrEq( pszEventName, "object_destroyed" );
+ int iCustomDamage = event->GetInt( "customkill" );
+ int iLocalPlayerIndex = GetLocalPlayerIndex();
+
+ const int iKillerID = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
+ const int iVictimID = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
+ // if there was an assister, put both the killer's and assister's names in the death message
+ int iAssisterID = engine->GetPlayerForUserID( event->GetInt( "assister" ) );
+
+ EHorriblePyroVisionHack ePyroVisionHack = kHorriblePyroVisionHack_KillAssisterType_Default;
+ CUtlConstString sAssisterNameScratch;
+ const char *assister_name = ( iAssisterID > 0 ? g_PR->GetPlayerName( iAssisterID ) : NULL );
+
+ // If we don't have a real assister (would have been passed in to us as a player index) and
+ // we're in crazy pyrovision mode and we got a dummy assister, than fall back and display
+ // that just for giggles. We use this so the Balloonicorn and friends can get the assist
+ // credit they so rightly deserve.
+ if ( !assister_name && bIsSillyPyroVision )
+ {
+ // Ignore this for self-kills.
+ if ( bIsObjectDestroyed || (iKillerID != iVictimID) )
+ {
+ const char *pszMaybeFallbackAssisterName = event->GetString( "assister_fallback" );
+ if ( pszMaybeFallbackAssisterName && pszMaybeFallbackAssisterName[0] )
+ {
+ // We store the type of silly assist in the first byte of the string because we
+ // are terrible people.
+ ePyroVisionHack = (EHorriblePyroVisionHack)pszMaybeFallbackAssisterName[0];
+ Assert( ePyroVisionHack != kHorriblePyroVisionHack_KillAssisterType_Default );
+ pszMaybeFallbackAssisterName = &pszMaybeFallbackAssisterName[1];
+
+ // If we pass in a localization string, we need to convert it back to ANSI temporarily.
+ // This won't localize "The" Balloonicorn because we don't have a real item with a real
+ // quality, etc., just a single localization token.
+ switch ( ePyroVisionHack )
+ {
+ case kHorriblePyroVisionHack_KillAssisterType_LocalizationString:
+ case kHorriblePyroVisionHack_KillAssisterType_LocalizationString_First:
+ {
+ wchar_t *wszLocalizedItemName = GLocalizationProvider()->Find( pszMaybeFallbackAssisterName );
+ char szANSIConvertedItemName[ MAX_PLAYER_NAME_LENGTH ];
+ g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalizedItemName, szANSIConvertedItemName, MAX_PLAYER_NAME_LENGTH );
+ sAssisterNameScratch = szANSIConvertedItemName;
+ assister_name = sAssisterNameScratch.Get();
+ break;
+ }
+ case kHorriblePyroVisionHack_KillAssisterType_CustomName:
+ case kHorriblePyroVisionHack_KillAssisterType_CustomName_First:
+ {
+ sAssisterNameScratch = pszMaybeFallbackAssisterName;
+ assister_name = sAssisterNameScratch.Get();
+ break;
+ }
+ default:
+ assert( !"Unknown pyro item hack type! Something has gone horribly, horribly worse." );
+ }
+ }
+ }
+ }
+
+ bool bMultipleKillers = false;
+
+ if ( assister_name )
+ {
+ DeathNoticeItem &msg = m_DeathNotices[ iDeathNoticeMsg ];
+ const char *pszKillerName = msg.Killer.szName;
+ const char *pszAssisterName = assister_name;
+
+ // Check to see if we're swapping the killer and the assister. We use this so the brain slug can get the kill
+ // credit for the HUD death notices, with the player being the assister.
+ if ( pszAssisterName && (ePyroVisionHack == kHorriblePyroVisionHack_KillAssisterType_CustomName_First ||
+ ePyroVisionHack == kHorriblePyroVisionHack_KillAssisterType_LocalizationString_First) )
+ {
+ std::swap( pszKillerName, pszAssisterName );
+ }
+
+ char szKillerBuf[MAX_PLAYER_NAME_LENGTH*2];
+ Q_snprintf( szKillerBuf, ARRAYSIZE(szKillerBuf), "%s + %s", pszKillerName, pszAssisterName );
+ Q_strncpy( msg.Killer.szName, szKillerBuf, ARRAYSIZE( msg.Killer.szName ) );
+ if ( iLocalPlayerIndex == iAssisterID )
+ {
+ msg.bLocalPlayerInvolved = true;
+ }
+
+ bMultipleKillers = true;
+ }
+
+ // play an exciting sound if a sniper pulls off any sort of penetration kill
+ const int iPlayerPenetrationCount = !event->IsEmpty( "playerpenetratecount" ) ? event->GetInt( "playerpenetratecount" ) : 0;
+
+ bool bPenetrateSound = iPlayerPenetrationCount > 0;
+
+ // This happens too frequently in Coop/TD
+ if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
+ {
+ bPenetrateSound = false;
+ }
+
+ if ( bPenetrateSound )
+ {
+ CLocalPlayerFilter filter;
+ C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "Game.PenetrationKill" );
+ }
+
+
+ int deathFlags = event->GetInt( "death_flags" );
+
+ if ( !bIsObjectDestroyed )
+ {
+ // if this death involved a player dominating another player or getting revenge on another player, add an additional message
+ // mentioning that
+
+ // WARNING: AddAdditionalMsg will grow and potentially realloc the m_DeathNotices array. So be careful
+ // using pointers to m_DeathNotices elements...
+
+ if ( deathFlags & TF_DEATH_DOMINATION )
+ {
+ AddAdditionalMsg( iKillerID, iVictimID, bIsSillyPyroVision ? "#Msg_Dominating_What" : "#Msg_Dominating" );
+ PlayRivalrySounds( iKillerID, iVictimID, TF_DEATH_DOMINATION );
+ }
+ if ( deathFlags & TF_DEATH_ASSISTER_DOMINATION && ( iAssisterID > 0 ) )
+ {
+ AddAdditionalMsg( iAssisterID, iVictimID, bIsSillyPyroVision ? "#Msg_Dominating_What" : "#Msg_Dominating" );
+ PlayRivalrySounds( iAssisterID, iVictimID, TF_DEATH_DOMINATION );
+ }
+ if ( deathFlags & TF_DEATH_REVENGE )
+ {
+ AddAdditionalMsg( iKillerID, iVictimID, bIsSillyPyroVision ? "#Msg_Revenge_What" : "#Msg_Revenge" );
+ PlayRivalrySounds( iKillerID, iVictimID, TF_DEATH_REVENGE );
+ }
+ if ( deathFlags & TF_DEATH_ASSISTER_REVENGE && ( iAssisterID > 0 ) )
+ {
+ AddAdditionalMsg( iAssisterID, iVictimID, bIsSillyPyroVision ? "#Msg_Revenge_What" : "#Msg_Revenge" );
+ PlayRivalrySounds( iAssisterID, iVictimID, TF_DEATH_REVENGE );
+ }
+ }
+ else
+ {
+ // if this is an object destroyed message, set the victim name to "<object type> (<owner>)"
+ int iObjectType = event->GetInt( "objecttype" );
+ if ( iObjectType >= 0 && iObjectType < OBJ_LAST )
+ {
+ // get the localized name for the object
+ char szLocalizedObjectName[MAX_PLAYER_NAME_LENGTH];
+ szLocalizedObjectName[ 0 ] = 0;
+ const wchar_t *wszLocalizedObjectName = g_pVGuiLocalize->Find( szLocalizedObjectNames[iObjectType] );
+ if ( wszLocalizedObjectName )
+ {
+ g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalizedObjectName, szLocalizedObjectName, ARRAYSIZE( szLocalizedObjectName ) );
+ }
+ else
+ {
+ Warning( "Couldn't find localized object name for '%s'\n", szLocalizedObjectNames[iObjectType] );
+ Q_strncpy( szLocalizedObjectName, szLocalizedObjectNames[iObjectType], sizeof( szLocalizedObjectName ) );
+ }
+
+ // compose the string
+ DeathNoticeItem &msg = m_DeathNotices[ iDeathNoticeMsg ];
+ if ( msg.Victim.szName[0] )
+ {
+ char szVictimBuf[MAX_PLAYER_NAME_LENGTH*2];
+ Q_snprintf( szVictimBuf, ARRAYSIZE(szVictimBuf), "%s (%s)", szLocalizedObjectName, msg.Victim.szName );
+ Q_strncpy( msg.Victim.szName, szVictimBuf, ARRAYSIZE( msg.Victim.szName ) );
+ }
+ else
+ {
+ Q_strncpy( msg.Victim.szName, szLocalizedObjectName, ARRAYSIZE( msg.Victim.szName ) );
+ }
+
+ }
+ else
+ {
+ Assert( false ); // invalid object type
+ }
+ }
+
+ const wchar_t *pMsg = NULL;
+ DeathNoticeItem &msg = m_DeathNotices[ iDeathNoticeMsg ];
+
+ switch ( iCustomDamage )
+ {
+ case TF_DMG_CUSTOM_BACKSTAB:
+ if ( FStrEq( msg.szIcon, "d_sharp_dresser" ) )
+ {
+ Q_strncpy( msg.szIcon, "d_sharp_dresser_backstab", ARRAYSIZE( msg.szIcon ) );
+ }
+ else
+ {
+ Q_strncpy( msg.szIcon, "d_backstab", ARRAYSIZE( msg.szIcon ) );
+ }
+ break;
+ case TF_DMG_CUSTOM_HEADSHOT_DECAPITATION:
+ case TF_DMG_CUSTOM_HEADSHOT:
+ {
+ if ( FStrEq( event->GetString( "weapon" ), "ambassador" ) )
+ {
+ Q_strncpy( msg.szIcon, "d_ambassador_headshot", ARRAYSIZE( msg.szIcon ) );
+ }
+ else if ( FStrEq( event->GetString( "weapon" ), "huntsman" ) )
+ {
+ Q_strncpy( msg.szIcon, "d_huntsman_headshot", ARRAYSIZE( msg.szIcon ) );
+ }
+ else
+ {
+ // Did this headshot penetrate something before the kill? If so, show a fancy icon
+ // so the player feels proud.
+ if ( iPlayerPenetrationCount > 0 )
+ {
+ Q_strncpy( msg.szIcon, "d_headshot_player_penetration", ARRAYSIZE( msg.szIcon ) );
+ }
+ else
+ {
+ Q_strncpy( msg.szIcon, "d_headshot", ARRAYSIZE( msg.szIcon ) );
+ }
+ }
+
+ break;
+ }
+ case TF_DMG_CUSTOM_BURNING:
+ if ( event->GetInt( "attacker" ) == event->GetInt( "userid" ) )
+ {
+ // suicide by fire
+ Q_strncpy( msg.szIcon, "d_firedeath", ARRAYSIZE( msg.szIcon ) );
+ msg.wzInfoText[0] = 0;
+ }
+ break;
+
+ case TF_DMG_CUSTOM_BURNING_ARROW:
+ // special-case if the player is killed from a burning arrow after it has already landed
+ Q_strncpy( msg.szIcon, "d_huntsman_burning", ARRAYSIZE( msg.szIcon ) );
+ msg.wzInfoText[0] = 0;
+ break;
+
+ case TF_DMG_CUSTOM_FLYINGBURN:
+ // special-case if the player is killed from a burning arrow as the killing blow
+ Q_strncpy( msg.szIcon, "d_huntsman_flyingburn", ARRAYSIZE( msg.szIcon ) );
+ msg.wzInfoText[0] = 0;
+ break;
+
+ case TF_DMG_CUSTOM_PUMPKIN_BOMB:
+ // special-case if the player is killed by a pumpkin bomb
+ Q_strncpy( msg.szIcon, "d_pumpkindeath", ARRAYSIZE( msg.szIcon ) );
+ msg.wzInfoText[0] = 0;
+ break;
+
+ case TF_DMG_CUSTOM_SUICIDE:
+ {
+ // display a different message if this was suicide, or assisted suicide (suicide w/recent damage, kill awarded to damager)
+ bool bAssistedSuicide = event->GetInt( "userid" ) != event->GetInt( "attacker" );
+ pMsg = g_pVGuiLocalize->Find( ( bAssistedSuicide ) ? ( bMultipleKillers ? "#DeathMsg_AssistedSuicide_Multiple" : "#DeathMsg_AssistedSuicide" ) : ( "#DeathMsg_Suicide" ) );
+ if ( pMsg )
+ {
+ V_wcsncpy( msg.wzInfoText, pMsg, sizeof( msg.wzInfoText ) );
+ }
+ break;
+ }
+ case TF_DMG_CUSTOM_EYEBALL_ROCKET:
+ {
+ if ( msg.Killer.iTeam == TEAM_UNASSIGNED )
+ {
+ char szLocalizedName[MAX_PLAYER_NAME_LENGTH];
+ szLocalizedName[ 0 ] = 0;
+ const wchar_t *wszLocalizedName = g_pVGuiLocalize->Find( "#TF_HALLOWEEN_EYEBALL_BOSS_DEATHCAM_NAME" );
+ if ( wszLocalizedName )
+ {
+ g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalizedName, szLocalizedName, ARRAYSIZE( szLocalizedName ) );
+ Q_strncpy( msg.Killer.szName, szLocalizedName, ARRAYSIZE( msg.Killer.szName ) );
+ msg.Killer.iTeam = TF_TEAM_HALLOWEEN; // This will set the name to purple for MONOCULUS!
+ }
+ }
+ break;
+ }
+ case TF_DMG_CUSTOM_MERASMUS_ZAP:
+ case TF_DMG_CUSTOM_MERASMUS_GRENADE:
+ case TF_DMG_CUSTOM_MERASMUS_DECAPITATION:
+ {
+ if ( msg.Killer.iTeam == TEAM_UNASSIGNED )
+ {
+ char szLocalizedName[MAX_PLAYER_NAME_LENGTH];
+ szLocalizedName[ 0 ] = 0;
+ const wchar_t *wszLocalizedName = g_pVGuiLocalize->Find( "#TF_HALLOWEEN_MERASMUS_DEATHCAM_NAME" );
+ if ( wszLocalizedName )
+ {
+ g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalizedName, szLocalizedName, ARRAYSIZE( szLocalizedName ) );
+ Q_strncpy( msg.Killer.szName, szLocalizedName, ARRAYSIZE( msg.Killer.szName ) );
+ msg.Killer.iTeam = TF_TEAM_HALLOWEEN; // This will set the name to green for MERASMUS!
+ }
+ }
+ break;
+ }
+ case TF_DMG_CUSTOM_SPELL_SKELETON:
+ {
+ if ( msg.Killer.iTeam == TEAM_UNASSIGNED )
+ {
+ char szLocalizedName[MAX_PLAYER_NAME_LENGTH];
+ szLocalizedName[ 0 ] = 0;
+ const wchar_t *wszLocalizedName = g_pVGuiLocalize->Find( "#TF_HALLOWEEN_SKELETON_DEATHCAM_NAME" );
+ if ( wszLocalizedName )
+ {
+ g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalizedName, szLocalizedName, ARRAYSIZE( szLocalizedName ) );
+ Q_strncpy( msg.Killer.szName, szLocalizedName, ARRAYSIZE( msg.Killer.szName ) );
+ msg.Killer.iTeam = TF_TEAM_HALLOWEEN; // This will set the name to green for THE UNDEAD!
+ }
+ }
+ break;
+ }
+
+ case TF_DMG_CUSTOM_KART:
+ // special-case if the player is pushed by kart
+ Q_strncpy( msg.szIcon, "d_bumper_kart", ARRAYSIZE( msg.szIcon ) );
+ msg.wzInfoText[0] = 0;
+ break;
+ case TF_DMG_CUSTOM_GIANT_HAMMER:
+ // special-case Giant hammer
+ Q_strncpy( msg.szIcon, "d_necro_smasher", ARRAYSIZE( msg.szIcon ) );
+ msg.wzInfoText[0] = 0;
+ break;
+ default:
+ break;
+ }
+
+ if ( ( event->GetInt( "damagebits" ) & DMG_NERVEGAS ) )
+ {
+ // special case icon for hit-by-vehicle death
+ Q_strncpy( msg.szIcon, "d_saw_kill", ARRAYSIZE( msg.szIcon ) );
+ }
+
+ int iKillStreakTotal = event->GetInt( "kill_streak_total" );
+ int iKillStreakWep = event->GetInt( "kill_streak_wep" );
+ int iDuckStreakTotal = event->GetInt( "duck_streak_total" );
+ int iDucksThisKill = event->GetInt( "ducks_streaked" );
+
+ // if the active weapon is kill streak
+ C_TFPlayer* pKiller = ToTFPlayer( UTIL_PlayerByIndex( iKillerID ) );
+ C_TFPlayer* pVictim = ToTFPlayer( UTIL_PlayerByIndex( iVictimID ) );
+ C_TFPlayer* pAssister = ToTFPlayer( UTIL_PlayerByIndex( iAssisterID ) );
+
+ // Mannpower runes
+ if ( pKiller && pKiller->m_Shared.IsCarryingRune() )
+ {
+ msg.iconPreKillerName = GetMannPowerIcon( pKiller->m_Shared.GetCarryingRuneType(), pKiller->GetTeamNumber() == TF_TEAM_RED );
+ }
+
+ if ( pVictim && pVictim->m_Shared.IsCarryingRune() )
+ {
+ msg.iconPostVictimName = GetMannPowerIcon( pVictim->m_Shared.GetCarryingRuneType(), pVictim->GetTeamNumber() == TF_TEAM_RED );
+ }
+
+ if ( iKillStreakWep > 0 )
+ {
+ // append kill streak count to this notification
+ wchar_t wzCount[10];
+ _snwprintf( wzCount, ARRAYSIZE( wzCount ), L"%d", iKillStreakWep );
+ g_pVGuiLocalize->ConstructString_safe( msg.wzPreKillerText, g_pVGuiLocalize->Find("#Kill_Streak"), 1, wzCount );
+ if ( msg.bLocalPlayerInvolved )
+ {
+ msg.iconPostKillerName = m_iconKillStreakDNeg;
+ }
+ else
+ {
+ msg.iconPostKillerName = m_iconKillStreak;
+ }
+ }
+ else if ( iDuckStreakTotal > 0 && iDucksThisKill )
+ {
+ // Duckstreak icon (always lower priority)
+ wchar_t wzCount[10];
+ _snwprintf( wzCount, ARRAYSIZE( wzCount ), L"%d", iDuckStreakTotal );
+ g_pVGuiLocalize->ConstructString_safe( msg.wzPreKillerText, g_pVGuiLocalize->Find("#Duck_Streak"), 1, wzCount );
+ msg.iconPostKillerName = msg.bLocalPlayerInvolved ? m_iconDuckStreakDNeg : m_iconDuckStreak;
+ }
+
+ // Check to see if we want a extra notification
+ // Attempt to display these in order of descending priority
+
+ // Check Assister for Additional Messages
+ int iKillStreakAssist = event->GetInt( "kill_streak_assist" );
+ int iKillStreakVictim = event->GetInt( "kill_streak_victim" );
+
+ // Kills
+ AddStreakMsg( CTFPlayerShared::kTFStreak_Kills, iKillerID, iKillStreakTotal, 1, iVictimID, iDeathNoticeMsg );
+ if ( pAssister && iKillStreakAssist > 1 )
+ {
+ AddStreakMsg( CTFPlayerShared::kTFStreak_Kills, iAssisterID, iKillStreakAssist, 1, iVictimID, iDeathNoticeMsg );
+ }
+
+ if ( pVictim && iKillStreakVictim > 2 )
+ {
+ AddStreakEndedMsg( CTFPlayerShared::kTFStreak_Kills, iKillerID, iVictimID, iKillStreakVictim, iDeathNoticeMsg );
+ }
+
+ // Ducks
+ int iDuckStreakAssist = event->GetInt( "duck_streak_assist" );
+ int iDuckStreakVictim = event->GetInt( "duck_streak_victim" );
+ int iDuckStreakIncrement = event->GetInt( "ducks_streaked" );
+
+ AddStreakMsg( CTFPlayerShared::kTFStreak_Ducks, iKillerID, iDuckStreakTotal, iDuckStreakIncrement, iVictimID, iDeathNoticeMsg );
+ if ( pAssister && iDuckStreakAssist > 0 && iDucksThisKill )
+ {
+ AddStreakMsg( CTFPlayerShared::kTFStreak_Ducks, iAssisterID, iDuckStreakAssist, iDuckStreakIncrement, iVictimID, iDeathNoticeMsg );
+ }
+
+ if ( pVictim && iDuckStreakVictim > 2 )
+ {
+ AddStreakEndedMsg( CTFPlayerShared::kTFStreak_Ducks, iKillerID, iVictimID, iDuckStreakVictim, iDeathNoticeMsg );
+ }
+
+ // STAGING ONLY test
+ // If Local Player killed someone and they have an item waiting, let them know
+#ifdef STAGING_ONLY
+ //if ( iLocalPlayerIndex == iKillerID && m_bShowItemOnKill )
+ //{
+ // if ( CEconNotification_HasNewItemsOnKill::HasUnacknowledgedItems() )
+ // {
+ // CEconNotification_HasNewItemsOnKill *pNotification = new CEconNotification_HasNewItemsOnKill( iVictimID );
+ // NotificationQueue_Add( pNotification );
+ // m_bShowItemOnKill = false;
+ // }
+ //}
+ //if ( iLocalPlayerIndex == iVictimID )
+ //{
+ // m_bShowItemOnKill = true;
+ //}
+#endif
+ }
+ else if ( FStrEq( "teamplay_point_captured", pszEventName ) ||
+ FStrEq( "teamplay_capture_blocked", pszEventName ) ||
+ FStrEq( "teamplay_flag_event", pszEventName ) )
+ {
+ bool bDefense = ( FStrEq( "teamplay_capture_blocked", pszEventName ) || ( FStrEq( "teamplay_flag_event", pszEventName ) &&
+ TF_FLAGEVENT_DEFEND == event->GetInt( "eventtype" ) ) );
+
+ DeathNoticeItem &msg = m_DeathNotices[ iDeathNoticeMsg ];
+ const char *szCaptureIcons[] = { "d_redcapture", "d_bluecapture" };
+ const char *szDefenseIcons[] = { "d_reddefend", "d_bluedefend" };
+
+ int iTeam = msg.Killer.iTeam;
+ Assert( iTeam >= FIRST_GAME_TEAM );
+ Assert( iTeam < FIRST_GAME_TEAM + TF_TEAM_COUNT );
+ if ( iTeam < FIRST_GAME_TEAM || iTeam >= FIRST_GAME_TEAM + TF_TEAM_COUNT )
+ return;
+
+ int iIndex = msg.Killer.iTeam - FIRST_GAME_TEAM;
+ Assert( iIndex < ARRAYSIZE( szCaptureIcons ) );
+
+ Q_strncpy( msg.szIcon, bDefense ? szDefenseIcons[iIndex] : szCaptureIcons[iIndex], ARRAYSIZE( msg.szIcon ) );
+ }
+ else if ( FStrEq( "fish_notice", pszEventName ) || FStrEq( "fish_notice__arm", pszEventName ) )
+ {
+ DeathNoticeItem &msg = m_DeathNotices[ iDeathNoticeMsg ];
+ int deathFlags = event->GetInt( "death_flags" );
+ int iCustomDamage = event->GetInt( "customkill" );
+
+ if ( ( iCustomDamage == TF_DMG_CUSTOM_FISH_KILL ) || ( deathFlags & TF_DEATH_FEIGN_DEATH ) )
+ {
+ g_pVGuiLocalize->ConstructString_safe( msg.wzInfoText, FStrEq( "fish_notice", pszEventName ) ? g_pVGuiLocalize->Find("#Humiliation_Kill") : g_pVGuiLocalize->Find("#Humiliation_Kill_Arm"), 0 );
+ }
+ else
+ {
+ wchar_t wzCount[10];
+ _snwprintf( wzCount, ARRAYSIZE( wzCount ), L"%d", ++msg.iCount );
+ g_pVGuiLocalize->ConstructString_safe( msg.wzInfoText, g_pVGuiLocalize->Find("#Humiliation_Count"), 1, wzCount );
+ }
+
+ // if there was an assister, put both the killer's and assister's names in the death message
+ int iAssisterID = engine->GetPlayerForUserID( event->GetInt( "assister" ) );
+ const char *assister_name = ( iAssisterID > 0 ? g_PR->GetPlayerName( iAssisterID ) : NULL );
+ if ( assister_name )
+ {
+ char szKillerBuf[MAX_PLAYER_NAME_LENGTH*2];
+ Q_snprintf( szKillerBuf, ARRAYSIZE(szKillerBuf), "%s + %s", msg.Killer.szName, assister_name );
+ Q_strncpy( msg.Killer.szName, szKillerBuf, ARRAYSIZE( msg.Killer.szName ) );
+ }
+ }
+ //else if ( FStrEq( "throwable_hit", pszEventName ) )
+ //{
+ // DeathNoticeItem &msg = m_DeathNotices[ iDeathNoticeMsg ];
+ // int deathFlags = event->GetInt( "death_flags" );
+ // int iCustomDamage = event->GetInt( "customkill" );
+
+ // // Make sure the icon is up to date
+ // m_DeathNotices[iDeathNoticeMsg].iconDeath = GetIcon( m_DeathNotices[ iDeathNoticeMsg ].szIcon, m_DeathNotices[iDeathNoticeMsg].bLocalPlayerInvolved ? kDeathNoticeIcon_Inverted : kDeathNoticeIcon_Standard );
+
+ // if ( ( iCustomDamage == TF_DMG_CUSTOM_THROWABLE_KILL ) || ( deathFlags & TF_DEATH_FEIGN_DEATH ) )
+ // {
+ // g_pVGuiLocalize->ConstructString_safe( msg.wzInfoText, g_pVGuiLocalize->Find("#Throwable_Kill"), 0 );
+ // }
+ // else
+ // {
+ // wchar_t wzCount[10];
+ // _snwprintf( wzCount, ARRAYSIZE( wzCount ), L"%d", event->GetInt( "totalhits" ) );
+ // g_pVGuiLocalize->ConstructString_safe( msg.wzInfoText, g_pVGuiLocalize->Find("#Humiliation_Count"), 1, wzCount );
+ // }
+
+ // // if there was an assister, put both the killer's and assister's names in the death message
+ // int iAssisterID = engine->GetPlayerForUserID( event->GetInt( "assister" ) );
+ // const char *assister_name = ( iAssisterID > 0 ? g_PR->GetPlayerName( iAssisterID ) : NULL );
+ // if ( assister_name )
+ // {
+ // char szKillerBuf[MAX_PLAYER_NAME_LENGTH*2];
+ // Q_snprintf( szKillerBuf, ARRAYSIZE(szKillerBuf), "%s + %s", msg.Killer.szName, assister_name );
+ // Q_strncpy( msg.Killer.szName, szKillerBuf, ARRAYSIZE( msg.Killer.szName ) );
+ // }
+ //}
+ else if ( FStrEq( "rd_robot_killed", pszEventName ) )
+ {
+ DeathNoticeItem &msg = m_DeathNotices[ iDeathNoticeMsg ];
+
+ int killer = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
+ const char *killedwith = event->GetString( "weapon" );
+
+ msg.Killer.iTeam = g_PR->GetTeam( killer );
+ Q_strncpy( msg.Killer.szName, g_PR->GetPlayerName( killer ), ARRAYSIZE( msg.Killer.szName ) );
+
+ Q_strncpy( msg.Victim.szName, g_PR->GetTeam( killer ) == TF_TEAM_RED ? "BLUE ROBOT" : "RED ROBOT", ARRAYSIZE( msg.Victim.szName ) );
+ msg.Victim.iTeam = g_PR->GetTeam( killer ) == TF_TEAM_RED ? TF_TEAM_BLUE : TF_TEAM_RED;
+
+ Q_snprintf( msg.szIcon, sizeof(msg.szIcon), "d_%s", killedwith );
+ }
+ else if ( FStrEq( PasstimeGameEvents::BallGet::s_eventName, pszEventName ) ) // passtime ball get
+ {
+ PasstimeGameEvents::BallGet ev( event );
+ DeathNoticeItem &msg = m_DeathNotices[ iDeathNoticeMsg ];
+
+ // info
+ V_wcsncpy( msg.wzInfoText, g_pVGuiLocalize->Find("#Msg_PasstimeBallGet"), sizeof( msg.wzInfoText ) );
+
+ // killer
+ const char *szPlayerName = g_PR->GetPlayerName( ev.ownerIndex);
+ Q_strncpy( msg.Killer.szName, szPlayerName, ARRAYSIZE( msg.Killer.szName ) );
+ msg.Killer.iTeam = g_PR->GetTeam( ev.ownerIndex );
+
+ // flags
+ if ( GetLocalPlayerIndex() == ev.ownerIndex )
+ msg.bLocalPlayerInvolved = true;
+
+ // icon
+ const char *const icon = "d_passtime_pass";
+ Q_strncpy( msg.szIcon, icon, ARRAYSIZE( msg.szIcon ) );
+ }
+ else if ( FStrEq( PasstimeGameEvents::BallStolen::s_eventName, pszEventName ) ) // passtime ball stolen
+ {
+ PasstimeGameEvents::BallStolen ev( event );
+ DeathNoticeItem &msg = m_DeathNotices[ iDeathNoticeMsg ];
+
+ int attackerTeam = g_PR->GetTeam( ev.attackerIndex );
+ int victimTeam = g_PR->GetTeam( ev.victimIndex );
+
+ // attacker
+ const char *szPlayerName = g_PR->GetPlayerName( ev.attackerIndex );
+ Q_strncpy( msg.Killer.szName, szPlayerName, ARRAYSIZE( msg.Killer.szName ) );
+ msg.Killer.iTeam = attackerTeam;
+
+ // victim
+ szPlayerName = g_PR->GetPlayerName( ev.victimIndex );
+ Q_strncpy( msg.Victim.szName, szPlayerName, ARRAYSIZE( msg.Victim.szName ) );
+ msg.Victim.iTeam = victimTeam;
+
+ V_wcsncpy( msg.wzInfoText, g_pVGuiLocalize->Find("#Msg_PasstimeSteal"), sizeof( msg.wzInfoText ) );
+
+ // flags
+ int localPlayerIndex = GetLocalPlayerIndex();
+ msg.bLocalPlayerInvolved = (localPlayerIndex == ev.attackerIndex)
+ || (localPlayerIndex == ev.victimIndex);
+
+ // icon
+ Q_strncpy( msg.szIcon, "d_passtime_steal", ARRAYSIZE(msg.szIcon) );
+ }
+ else if ( FStrEq( PasstimeGameEvents::Score::s_eventName, pszEventName ) ) // passtime score
+ {
+ PasstimeGameEvents::Score ev( event );
+ DeathNoticeItem &msg = m_DeathNotices[ iDeathNoticeMsg ];
+
+ // info
+ if ( ev.numPoints > 1 )
+ {
+ wchar_t wzCount[10];
+ _snwprintf( wzCount, ARRAYSIZE( wzCount ), L"%d", ev.numPoints );
+ g_pVGuiLocalize->ConstructString_safe( msg.wzInfoText, g_pVGuiLocalize->Find("#Msg_PasstimeScoreCount"), 1, wzCount );
+ }
+ else
+ {
+ V_wcsncpy( msg.wzInfoText, g_pVGuiLocalize->Find("#Msg_PasstimeScore"), sizeof( msg.wzInfoText ) );
+ }
+
+ // killer
+ const char *szPlayerName = g_PR->GetPlayerName( ev.scorerIndex );
+ Q_strncpy( msg.Killer.szName, szPlayerName, ARRAYSIZE( msg.Killer.szName ) );
+ msg.Killer.iTeam = g_PR->GetTeam( ev.scorerIndex );
+
+ // flags
+ if ( GetLocalPlayerIndex() == ev.scorerIndex )
+ msg.bLocalPlayerInvolved = true;
+
+ // icon
+ const char *const icon = (msg.Killer.iTeam == TF_TEAM_RED)
+ ? "d_passtime_score_red"
+ : "d_passtime_score_blue";
+ Q_strncpy( msg.szIcon, icon, ARRAYSIZE( msg.szIcon ) );
+ }
+ else if ( FStrEq( PasstimeGameEvents::PassCaught::s_eventName, pszEventName ) ) // passtime pass
+ {
+ PasstimeGameEvents::PassCaught ev( event );
+ DeathNoticeItem &msg = m_DeathNotices[ iDeathNoticeMsg ];
+
+ int passerTeam = g_PR->GetTeam( ev.passerIndex );
+ int catcherTeam = g_PR->GetTeam( ev.catcherIndex );
+
+ //
+ // Pass or interception?
+ //
+ int killerIndex, victimIndex, killerTeam, victimTeam;
+ const char *pszDesc;
+ if ( passerTeam == catcherTeam )
+ {
+ // pass
+ killerIndex = ev.passerIndex;
+ killerTeam = passerTeam;
+ victimIndex = ev.catcherIndex;
+ victimTeam = catcherTeam;
+ pszDesc = "#Msg_PasstimePassComplete";
+ Q_strncpy( msg.szIcon, "d_passtime_pass", ARRAYSIZE(msg.szIcon) );
+ }
+ else
+ {
+ // interception
+ victimIndex = ev.passerIndex;
+ victimTeam = passerTeam;
+ killerIndex = ev.catcherIndex;
+ killerTeam = catcherTeam;
+ pszDesc = "#Msg_PasstimeInterception";
+ Q_strncpy( msg.szIcon, "d_passtime_intercept", ARRAYSIZE(msg.szIcon) );
+ }
+
+ // killer
+ const char *szPlayerName = g_PR->GetPlayerName( killerIndex );
+ Q_strncpy( msg.Killer.szName, szPlayerName, ARRAYSIZE( msg.Killer.szName ) );
+ msg.Killer.iTeam = killerTeam;
+
+ // victim
+ szPlayerName = g_PR->GetPlayerName( victimIndex );
+ Q_strncpy( msg.Victim.szName, szPlayerName, ARRAYSIZE( msg.Victim.szName ) );
+ msg.Victim.iTeam = victimTeam;
+
+ V_wcsncpy( msg.wzInfoText, g_pVGuiLocalize->Find( pszDesc ), sizeof( msg.wzInfoText ) );
+
+ // flags
+ int localPlayerIndex = GetLocalPlayerIndex();
+ msg.bLocalPlayerInvolved = (localPlayerIndex == ev.catcherIndex)
+ || (localPlayerIndex == ev.passerIndex);
+ }
+ else if ( FStrEq( PasstimeGameEvents::BallBlocked::s_eventName, pszEventName ) ) // passtime ball stolen
+ {
+ PasstimeGameEvents::BallBlocked ev( event );
+ DeathNoticeItem &msg = m_DeathNotices[ iDeathNoticeMsg ];
+
+ // blocker
+ const char *szPlayerName = g_PR->GetPlayerName( ev.blockerIndex );
+ Q_strncpy( msg.Killer.szName, szPlayerName, ARRAYSIZE( msg.Killer.szName ) );
+ msg.Killer.iTeam = g_PR->GetTeam( ev.blockerIndex );
+
+ // owner
+ szPlayerName = g_PR->GetPlayerName( ev.ownerIndex );
+ Q_strncpy( msg.Victim.szName, szPlayerName, ARRAYSIZE( msg.Victim.szName ) );
+ msg.Victim.iTeam = g_PR->GetTeam( ev.ownerIndex );
+
+ V_wcsncpy( msg.wzInfoText, g_pVGuiLocalize->Find("#Msg_PasstimeBlock"), sizeof( msg.wzInfoText ) );
+
+ // flags
+ int localPlayerIndex = GetLocalPlayerIndex();
+ msg.bLocalPlayerInvolved = (localPlayerIndex == ev.blockerIndex)
+ || (localPlayerIndex == ev.ownerIndex);
+
+ // icon
+ Q_strncpy( msg.szIcon, "d_ball", ARRAYSIZE(msg.szIcon) );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds an additional death message
+//-----------------------------------------------------------------------------
+void CTFHudDeathNotice::AddAdditionalMsg( int iKillerID, int iVictimID, const char *pMsgKey )
+{
+ DeathNoticeItem &msg2 = m_DeathNotices[AddDeathNoticeItem()];
+ Q_strncpy( msg2.Killer.szName, g_PR->GetPlayerName( iKillerID ), ARRAYSIZE( msg2.Killer.szName ) );
+ msg2.Killer.iTeam = g_PR->GetTeam( iKillerID );
+ Q_strncpy( msg2.Victim.szName, g_PR->GetPlayerName( iVictimID ), ARRAYSIZE( msg2.Victim.szName ) );
+ msg2.Victim.iTeam = g_PR->GetTeam( iVictimID );
+ const wchar_t *wzMsg = g_pVGuiLocalize->Find( pMsgKey );
+ if ( wzMsg )
+ {
+ V_wcsncpy( msg2.wzInfoText, wzMsg, sizeof( msg2.wzInfoText ) );
+ }
+ msg2.iconDeath = m_iconDomination;
+ int iLocalPlayerIndex = GetLocalPlayerIndex();
+ if ( iLocalPlayerIndex == iVictimID || iLocalPlayerIndex == iKillerID )
+ {
+ msg2.bLocalPlayerInvolved = true;
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CTFHudDeathNotice::AddStreakMsg( CTFPlayerShared::ETFStreak eStreakType, int iKillerID, int iKillerStreak, int iStreakIncrement, int iVictimID, int iDeathNoticeMsg )
+{
+ int nMinStreak = MinStreakForType( eStreakType );
+ if ( iKillerStreak < nMinStreak )
+ return;
+
+ if ( !m_pStreakNotice )
+ return;
+
+ if ( cl_hud_killstreak_display_time.GetInt() <= 0 )
+ return;
+
+ m_pStreakNotice->StreakUpdated( eStreakType, iKillerID, iKillerStreak, iStreakIncrement );
+}
+
+//-----------------------------------------------------------------------------
+void CTFHudDeathNotice::AddStreakEndedMsg( CTFPlayerShared::ETFStreak eStreakType, int iKillerID, int iVictimID, int iVictimStreak, int iDeathNoticeMsg )
+{
+ int nMinStreak = MinStreakForType( eStreakType );
+ if ( iVictimStreak < nMinStreak )
+ return;
+
+ if ( !m_pStreakNotice )
+ return;
+
+ if ( cl_hud_killstreak_display_time.GetInt() <= 0 )
+ return;
+
+ m_pStreakNotice->StreakEnded( eStreakType, iKillerID, iVictimID, iVictimStreak );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the color to draw text in for this team.
+//-----------------------------------------------------------------------------
+Color CTFHudDeathNotice::GetTeamColor( int iTeamNumber, bool bLocalPlayerInvolved /* = false */ )
+{
+ switch ( iTeamNumber )
+ {
+ case TF_TEAM_BLUE:
+ return m_clrBlueText;
+ break;
+ case TF_TEAM_RED:
+ return m_clrRedText;
+ break;
+ case TEAM_UNASSIGNED:
+ if ( bLocalPlayerInvolved )
+ return m_clrLocalPlayerText;
+ else
+ return Color( 255, 255, 255, 255 );
+ break;
+ case TF_TEAM_HALLOWEEN:
+ if ( TFGameRules() && ( TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_LAKESIDE ) || TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_HIGHTOWER ) ) )
+ {
+ return m_clrGreenText;
+ }
+ else
+ {
+ return m_clrPurpleText;
+ }
+ break;
+ default:
+ AssertOnce( false ); // invalid team
+ return Color( 255, 255, 255, 255 );
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+Color CTFHudDeathNotice::GetInfoTextColor( int iDeathNoticeMsg )
+{
+ DeathNoticeItem &msg = m_DeathNotices[ iDeathNoticeMsg ];
+
+ if ( msg.bLocalPlayerInvolved )
+ return m_clrLocalPlayerText;
+
+ return Color( 255, 255, 255, 255 );
+}
+
+//-----------------------------------------------------------------------------
+Color CTFHudDeathNotice::GetBackgroundColor ( int iDeathNoticeMsg )
+{
+ DeathNoticeItem &msg = m_DeathNotices[ iDeathNoticeMsg ];
+
+ return msg.bLocalPlayerInvolved ? m_clrLocalBGColor : m_clrBaseBGColor;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CTFHudDeathNotice::UseExistingNotice( IGameEvent *event )
+{
+ // Fish Notices and Throwables
+ // Add check for all throwables
+ int iTarget = event->GetInt( "weaponid" );
+ if (iTarget == TF_WEAPON_BAT_FISH || iTarget == TF_WEAPON_THROWABLE || iTarget == TF_WEAPON_GRENADE_THROWABLE )
+ {
+ // Look for a matching pre-existing notice.
+ for ( int i=0; i<m_DeathNotices.Count(); ++i )
+ {
+ DeathNoticeItem &msg = m_DeathNotices[i];
+
+ if ( msg.iWeaponID != iTarget )
+ continue;
+
+ if ( msg.iKillerID != event->GetInt( "attacker" ) )
+ continue;
+
+ if ( msg.iVictimID != event->GetInt( "userid" ) )
+ continue;
+
+ return i;
+ }
+ }
+
+ return BaseClass::UseExistingNotice( event );
+}
+//-----------------------------------------------------------------------------
+CHudTexture* CTFHudDeathNotice::GetMannPowerIcon( RuneTypes_t tRuneType, bool bIsRedTeam )
+{
+ // Red team is normal file and blue is dNeg file
+ switch ( tRuneType )
+ {
+ case RUNE_STRENGTH: return bIsRedTeam ? gHUD.GetIcon( "d_mannpower_strength" ) : gHUD.GetIcon( "dneg_mannpower_strength" );
+ case RUNE_HASTE: return bIsRedTeam ? gHUD.GetIcon( "d_mannpower_haste" ) : gHUD.GetIcon( "dneg_mannpower_haste" );
+ case RUNE_REGEN: return bIsRedTeam ? gHUD.GetIcon( "d_mannpower_regen" ) : gHUD.GetIcon( "dneg_mannpower_regen" );
+ case RUNE_RESIST: return bIsRedTeam ? gHUD.GetIcon( "d_mannpower_resist" ) : gHUD.GetIcon( "dneg_mannpower_resist" );
+ case RUNE_VAMPIRE: return bIsRedTeam ? gHUD.GetIcon( "d_mannpower_vamp" ) : gHUD.GetIcon( "dneg_mannpower_vamp" );
+ case RUNE_REFLECT: return bIsRedTeam ? gHUD.GetIcon( "d_mannpower_reflect" ) : gHUD.GetIcon( "dneg_mannpower_reflect" );
+ case RUNE_PRECISION: return bIsRedTeam ? gHUD.GetIcon( "d_mannpower_precision" ) : gHUD.GetIcon( "dneg_mannpower_precision" );
+ case RUNE_AGILITY: return bIsRedTeam ? gHUD.GetIcon( "d_mannpower_agility" ) : gHUD.GetIcon( "dneg_mannpower_agility" );
+ case RUNE_KNOCKOUT: return bIsRedTeam ? gHUD.GetIcon( "d_mannpower_fist" ) : gHUD.GetIcon( "dneg_mannpower_fist" );
+ case RUNE_KING: return bIsRedTeam ? gHUD.GetIcon( "d_mannpower_king" ) : gHUD.GetIcon( "dneg_mannpower_king" );
+ case RUNE_PLAGUE: return bIsRedTeam ? gHUD.GetIcon( "d_mannpower_plague" ) : gHUD.GetIcon( "dneg_mannpower_plague" );
+ case RUNE_SUPERNOVA: return bIsRedTeam ? gHUD.GetIcon( "d_mannpower_supernova" ) : gHUD.GetIcon( "dneg_mannpower_supernova" );
+ default: return NULL;
+ }
+ return NULL;
+} \ No newline at end of file