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