You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1635 lines
56 KiB
1635 lines
56 KiB
//========= 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; |
|
} |