hl2_src-leak-2017/src/game/client/tf/tf_hud_playerstatus.cpp

1158 lines
39 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "hudelement.h"
#include "iclientmode.h"
#include <KeyValues.h>
#include <vgui/IScheme.h>
#include <vgui/ISurface.h>
#include <vgui/ISystem.h>
#include <vgui_controls/AnimationController.h>
#include <vgui_controls/EditablePanel.h>
#include <vgui/ISurface.h>
#include <vgui/IImage.h>
#include <vgui_controls/Label.h>
#include "c_tf_playerresource.h"
#include "tf_playermodelpanel.h"
#include "econ_item_description.h"
#include "hud_numericdisplay.h"
#include "c_team.h"
#include "c_tf_player.h"
#include "tf_shareddefs.h"
#include "tf_hud_playerstatus.h"
#include "tf_gamerules.h"
#include "tf_logic_halloween_2014.h"
#include "tf_logic_player_destruction.h"
#include "tf_wheel_of_doom.h"
#include "confirm_dialog.h"
using namespace vgui;
ConVar cl_hud_playerclass_use_playermodel( "cl_hud_playerclass_use_playermodel", "1", FCVAR_ARCHIVE, "Use player model in player class HUD." );
#ifdef STAGING_ONLY
ConVar cl_hud_playerclass_playermodel_lod( "cl_hud_playerclass_playermodel_lod", "0", FCVAR_ARCHIVE, "Adjust lod on player model in the player class HUD." );
#endif // STAGING_ONLY
ConVar cl_hud_playerclass_playermodel_showed_confirm_dialog( "cl_hud_playerclass_playermodel_showed_confirm_dialog", "0", FCVAR_ARCHIVE | FCVAR_HIDDEN );
extern ConVar tf_max_health_boost;
static const char *g_szBlueClassImages[] =
{
"",
"../hud/class_scoutblue",
"../hud/class_sniperblue",
"../hud/class_soldierblue",
"../hud/class_demoblue",
"../hud/class_medicblue",
"../hud/class_heavyblue",
"../hud/class_pyroblue",
"../hud/class_spyblue",
"../hud/class_engiblue",
"../hud/class_scoutblue",
};
static const char *g_szRedClassImages[] =
{
"",
"../hud/class_scoutred",
"../hud/class_sniperred",
"../hud/class_soldierred",
"../hud/class_demored",
"../hud/class_medicred",
"../hud/class_heavyred",
"../hud/class_pyrored",
"../hud/class_spyred",
"../hud/class_engired",
"../hud/class_scoutred",
};
enum
{
HUD_HEALTH_NO_ANIM = 0,
HUD_HEALTH_BONUS_ANIM,
HUD_HEALTH_DYING_ANIM,
};
DECLARE_BUILD_FACTORY( CTFClassImage );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFHudPlayerClass::CTFHudPlayerClass( Panel *parent, const char *name ) : EditablePanel( parent, name )
{
m_pClassImage = NULL;
m_pClassImageBG = NULL;
m_pSpyImage = NULL;
m_pSpyOutlineImage = NULL;
m_pPlayerModelPanel = NULL;
m_pPlayerModelPanelBG = NULL;
m_pCarryingWeaponPanel = NULL;
m_pCarryingLabel = NULL;
m_pCarryingOwnerLabel = NULL;
m_pCarryingBG = NULL;
m_nTeam = TEAM_UNASSIGNED;
m_nClass = TF_CLASS_UNDEFINED;
m_nDisguiseTeam = TEAM_UNASSIGNED;
m_nDisguiseClass = TF_CLASS_UNDEFINED;
m_hDisguiseWeapon = NULL;
m_flNextThink = 0.0f;
m_nKillStreak = 0;
#ifdef STAGING_ONLY
m_nLOD = -1;
#endif // STAGING_ONLY
m_bUsePlayerModel = cl_hud_playerclass_use_playermodel.GetBool();
ListenForGameEvent( "localplayer_changedisguise" );
ListenForGameEvent( "post_inventory_application" );
ListenForGameEvent( "localplayer_pickup_weapon" );
for ( int i = 0; i < TF_CLASS_COUNT_ALL; i++ )
{
// The materials are given to vgui via the SetImage() function, which prepends
// the "vgui/", so we need to precache them with the same.
if ( g_szBlueClassImages[i] && g_szBlueClassImages[i][0] )
{
PrecacheMaterial( VarArgs( "vgui/%s", g_szBlueClassImages[i] ) );
PrecacheMaterial( VarArgs( "vgui/%s_cloak", g_szBlueClassImages[i] ) );
PrecacheMaterial( VarArgs( "vgui/%s_halfcloak", g_szBlueClassImages[i] ) );
}
if ( g_szRedClassImages[i] && g_szRedClassImages[i][0] )
{
PrecacheMaterial( VarArgs( "vgui/%s", g_szRedClassImages[i] ) );
PrecacheMaterial( VarArgs( "vgui/%s_cloak", g_szRedClassImages[i] ) );
PrecacheMaterial( VarArgs( "vgui/%s_halfcloak", g_szRedClassImages[i] ) );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFHudPlayerClass::Reset()
{
m_flNextThink = gpGlobals->curtime + 0.05f;
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HudSpyDisguiseHide" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFHudPlayerClass::ApplySchemeSettings( IScheme *pScheme )
{
// load control settings...
LoadControlSettings( "resource/UI/HudPlayerClass.res" );
m_nTeam = TEAM_UNASSIGNED;
m_nClass = TF_CLASS_UNDEFINED;
m_nDisguiseTeam = TEAM_UNASSIGNED;
m_nDisguiseClass = TF_CLASS_UNDEFINED;
m_hDisguiseWeapon = NULL;
m_flNextThink = 0.0f;
m_nCloakLevel = 0;
m_nLoadoutPosition = LOADOUT_POSITION_PRIMARY;
m_pClassImage = FindControl<CTFClassImage>( "PlayerStatusClassImage", false );
m_pClassImageBG = FindControl<CTFImagePanel>( "PlayerStatusClassImageBG", false );
m_pSpyImage = FindControl<CTFImagePanel>( "PlayerStatusSpyImage", false );
m_pSpyOutlineImage = FindControl<CTFImagePanel>( "PlayerStatusSpyOutlineImage", false );
m_pPlayerModelPanel = FindControl<CTFPlayerModelPanel>( "classmodelpanel", false );
m_pPlayerModelPanelBG = FindControl<CTFImagePanel>( "classmodelpanelBG", false );
m_pCarryingWeaponPanel = FindControl< EditablePanel >( "CarryingWeapon", false );
if ( m_pCarryingWeaponPanel )
{
m_pCarryingLabel = m_pCarryingWeaponPanel->FindControl< CExLabel >( "CarryingLabel" );
m_pCarryingOwnerLabel = m_pCarryingWeaponPanel->FindControl< Label >( "OwnerLabel" );
m_pCarryingBG = m_pCarryingWeaponPanel->FindControl< CTFImagePanel >( "CarryingBackground" );
}
BaseClass::ApplySchemeSettings( pScheme );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFHudPlayerClass::OnThink()
{
if ( m_flNextThink > gpGlobals->curtime )
return;
m_flNextThink = gpGlobals->curtime + 0.5f;
C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
if ( !pPlayer )
return;
bool bTeamChange = false;
// set our background colors
if ( m_nTeam != pPlayer->GetTeamNumber() )
{
bTeamChange = true;
m_nTeam = pPlayer->GetTeamNumber();
}
int nCloakLevel = 0;
bool bCloakChange = false;
float flInvis = pPlayer->GetPercentInvisible();
if ( flInvis > 0.9 )
{
nCloakLevel = 2;
}
else if ( flInvis > 0.1 )
{
nCloakLevel = 1;
}
if ( nCloakLevel != m_nCloakLevel )
{
m_nCloakLevel = nCloakLevel;
bCloakChange = true;
}
bool bLoadoutPositionChange = false;
int nLoadoutSlot = pPlayer->GetActiveTFWeapon() ? pPlayer->GetActiveTFWeapon()->GetAttributeContainer()->GetItem()->GetStaticData()->GetLoadoutSlot( m_nClass ) : LOADOUT_POSITION_PRIMARY;
if ( m_nLoadoutPosition != nLoadoutSlot )
{
m_nLoadoutPosition = nLoadoutSlot;
bLoadoutPositionChange = true;
}
bool bPlayerClassModeChange = false;
if ( m_bUsePlayerModel != cl_hud_playerclass_use_playermodel.GetBool() )
{
m_bUsePlayerModel = cl_hud_playerclass_use_playermodel.GetBool();
bPlayerClassModeChange = true;
}
#ifdef STAGING_ONLY
if ( m_nLOD != cl_hud_playerclass_playermodel_lod.GetInt() && m_pPlayerModelPanel )
{
m_nLOD = cl_hud_playerclass_playermodel_lod.GetInt();
m_pPlayerModelPanel->SetLOD( m_nLOD );
}
#endif // STAGING_ONLY
bool bForceEyeUpdate = false;
// set our class image
if ( m_nClass != pPlayer->GetPlayerClass()->GetClassIndex() || bTeamChange || bCloakChange || bLoadoutPositionChange || bPlayerClassModeChange ||
(
m_nClass == TF_CLASS_SPY &&
(
m_nDisguiseClass != pPlayer->m_Shared.GetDisguiseClass() ||
m_nDisguiseTeam != pPlayer->m_Shared.GetDisguiseTeam() ||
m_hDisguiseWeapon != pPlayer->m_Shared.GetDisguiseWeapon()
)
)
)
{
bForceEyeUpdate = true;
m_nClass = pPlayer->GetPlayerClass()->GetClassIndex();
if ( m_nClass == TF_CLASS_SPY && pPlayer->m_Shared.InCond( TF_COND_DISGUISED ) )
{
if ( !pPlayer->m_Shared.InCond( TF_COND_DISGUISING ) )
{
m_nDisguiseTeam = pPlayer->m_Shared.GetDisguiseTeam();
m_nDisguiseClass = pPlayer->m_Shared.GetDisguiseClass();
m_hDisguiseWeapon = pPlayer->m_Shared.GetDisguiseWeapon();
}
}
else
{
m_nDisguiseTeam = TEAM_UNASSIGNED;
m_nDisguiseClass = TF_CLASS_UNDEFINED;
m_hDisguiseWeapon = NULL;
}
if ( m_bUsePlayerModel && m_pPlayerModelPanel && m_pPlayerModelPanelBG )
{
m_pPlayerModelPanel->SetVisible( true );
m_pPlayerModelPanelBG->SetVisible( true );
UpdateModelPanel();
}
else if ( m_pClassImage && m_pSpyImage )
{
if ( m_pPlayerModelPanel )
m_pPlayerModelPanel->SetVisible( false );
if ( m_pPlayerModelPanelBG )
m_pPlayerModelPanelBG->SetVisible( false );
m_pClassImage->SetVisible( true );
m_pClassImageBG->SetVisible( true );
int iCloakState = 0;
if ( pPlayer->IsPlayerClass( TF_CLASS_SPY ) )
{
iCloakState = m_nCloakLevel;
}
if ( m_nDisguiseTeam != TEAM_UNASSIGNED || m_nDisguiseClass != TF_CLASS_UNDEFINED )
{
m_pSpyImage->SetVisible( true );
m_pClassImage->SetClass( m_nDisguiseTeam, m_nDisguiseClass, iCloakState );
}
else
{
m_pSpyImage->SetVisible( false );
m_pClassImage->SetClass( m_nTeam, m_nClass, iCloakState );
}
}
}
if ( m_pCarryingWeaponPanel )
{
// Don't show if we're disguised (the panels overlap)
bool bShowCarryingWeaponPanel = m_nDisguiseClass == TF_CLASS_UNDEFINED;
if ( pPlayer->GetActiveTFWeapon() && pPlayer->GetActiveTFWeapon()->GetAttributeContainer() )
{
CEconItemView* pItem = pPlayer->GetActiveTFWeapon()->GetAttributeContainer()->GetItem();
if ( pItem )
{
CSteamID playerSteamID;
pPlayer->GetSteamID( &playerSteamID );
// We're holding a weapon we dont own!
if ( playerSteamID.GetAccountID() != pItem->GetAccountID() && m_pCarryingLabel )
{
locchar_t wszLocString [128];
// Construct and set the weapon's name
g_pVGuiLocalize->ConstructString_safe( wszLocString, L"%s1", 1, CEconItemLocalizedFullNameGenerator( GLocalizationProvider(), pItem->GetItemDefinition(), pItem->GetItemQuality() ).GetFullName() );
m_pCarryingWeaponPanel->SetDialogVariable( "carrying", wszLocString );
// Get and set the rarity color of the weapon
const char* pszColorName = GetItemSchema()->GetRarityColor( pItem->GetItemDefinition()->GetRarity() );
pszColorName = pszColorName ? pszColorName : "TanLight";
if ( pszColorName )
{
m_pCarryingLabel->SetColorStr( pszColorName );
}
bool bHasOwner = false;
locchar_t wszPlayerName [128];
CBasePlayer *pOwner = GetPlayerByAccountID( pItem->GetAccountID() );
// Bots will not work here, so don't fill this out if there's no owner
if ( pOwner )
{
// Fill out the actual owner's name
locchar_t wszStolenString[128];
g_pVGuiLocalize->ConvertANSIToUnicode( pOwner->GetPlayerName(), wszPlayerName, sizeof(wszPlayerName) );
g_pVGuiLocalize->ConstructString_safe( wszStolenString, g_pVGuiLocalize->Find( "TF_WhoDropped" ), 1, wszPlayerName );
m_pCarryingOwnerLabel->SetText( wszStolenString );
bHasOwner = true;
}
else
{
m_pCarryingOwnerLabel->SetText( "" );
}
int nMaxWide = 0, nMaxTall = 0;
// Resize the panel to just be the width of whichever label is longer
int nTall, nWide;
m_pCarryingLabel->SizeToContents();
m_pCarryingLabel->GetContentSize( nWide, nTall );
nMaxWide = Max( nMaxWide, nWide );
nMaxTall = Max( nMaxTall, nTall );
m_pCarryingOwnerLabel->SizeToContents();
m_pCarryingOwnerLabel->GetContentSize( nWide, nTall );
nMaxWide = Max( nMaxWide, nWide );
nMaxTall = Max( nMaxTall, nTall );
m_pCarryingBG->SetWide( nMaxWide + ( m_pCarryingLabel->GetXPos() * 2 ) );
m_pCarryingBG->SetTall( bHasOwner ? m_pCarryingOwnerLabel->GetYPos() + m_pCarryingOwnerLabel->GetTall() + YRES( 2 )
: m_pCarryingLabel->GetYPos() + m_pCarryingLabel->GetTall() + YRES( 2 ) );
}
else
{
bShowCarryingWeaponPanel = false;
}
}
}
else
{
bShowCarryingWeaponPanel = false;
}
if ( CTFPlayerDestructionLogic::GetRobotDestructionLogic() && ( CTFPlayerDestructionLogic::GetRobotDestructionLogic()->GetType() == CTFPlayerDestructionLogic::TYPE_PLAYER_DESTRUCTION ) )
{
if ( pPlayer->HasTheFlag() )
{
bShowCarryingWeaponPanel = false;
}
}
m_pCarryingWeaponPanel->SetVisible( bShowCarryingWeaponPanel );
}
if ( m_bUsePlayerModel && m_pPlayerModelPanel )
{
bool bPlaySparks = false;
int iKillStreak = pPlayer->m_Shared.GetStreak( CTFPlayerShared::kTFStreak_Kills );
if ( iKillStreak != m_nKillStreak && iKillStreak > 0 )
{
bPlaySparks = true;
}
m_nKillStreak = iKillStreak;
m_pPlayerModelPanel->SetEyeGlowEffect( pPlayer->GetEyeGlowEffect(), pPlayer->GetEyeGlowColor( false ), pPlayer->GetEyeGlowColor( true ), bForceEyeUpdate, bPlaySparks );
}
}
static void HudPlayerClassUsePlayerModelDialogCallback( bool bConfirmed, void *pContext )
{
cl_hud_playerclass_use_playermodel.SetValue( bConfirmed );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFHudPlayerClass::UpdateModelPanel()
{
if ( !m_bUsePlayerModel )
{
return;
}
C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
if ( !pPlayer || !pPlayer->IsAlive() )
{
return;
}
if ( !cl_hud_playerclass_playermodel_showed_confirm_dialog.GetBool() )
{
// only show this message one time
ShowConfirmDialog( "#GameUI_HudPlayerClassUsePlayerModelDialogTitle",
"#GameUI_HudPlayerClassUsePlayerModelDialogMessage",
"#GameUI_HudPlayerClassUsePlayerModelDialogConfirm",
"#GameUI_HudPlayerClassUsePlayerModelDialogCancel",
&HudPlayerClassUsePlayerModelDialogCallback );
cl_hud_playerclass_playermodel_showed_confirm_dialog.SetValue( true );
}
// hide old UI
if ( m_pSpyImage )
m_pSpyImage->SetVisible( false );
if ( m_pClassImage )
m_pClassImage->SetVisible( false );
if ( m_pClassImageBG )
m_pClassImageBG->SetVisible( false );
if ( m_pPlayerModelPanel && m_pPlayerModelPanel->IsVisible() )
{
int nClass;
int nTeam;
int nItemSlot = m_nLoadoutPosition;
CEconItemView *pWeapon = NULL;
bool bDisguised = pPlayer->m_Shared.InCond( TF_COND_DISGUISED );
if ( bDisguised )
{
nClass = pPlayer->m_Shared.GetDisguiseClass();
nTeam = pPlayer->m_Shared.GetDisguiseTeam();
if ( pPlayer->m_Shared.GetDisguiseWeapon() )
{
CAttributeContainer *pCont = pPlayer->m_Shared.GetDisguiseWeapon()->GetAttributeContainer();
pWeapon = pCont ? pCont->GetItem() : NULL;
if ( pWeapon )
{
nItemSlot = pWeapon->GetStaticData()->GetLoadoutSlot( nClass );
}
}
}
else
{
nClass = pPlayer->GetPlayerClass()->GetClassIndex();
nTeam = pPlayer->GetTeamNumber();
CTFWeaponBase *pEnt = dynamic_cast< CTFWeaponBase* >( pPlayer->GetEntityForLoadoutSlot( nItemSlot ) );
if ( pEnt )
{
pWeapon = pEnt->GetAttributeContainer()->GetItem();
}
}
bool bIsRobot = false;
int iRobot = 0;
CALL_ATTRIB_HOOK_INT_ON_OTHER( pPlayer, iRobot, appear_as_mvm_robot );
bIsRobot = iRobot ? true : false;
m_pPlayerModelPanel->ClearCarriedItems();
m_pPlayerModelPanel->SetToPlayerClass( nClass, bIsRobot );
m_pPlayerModelPanel->SetTeam( nTeam );
if ( pWeapon )
{
m_pPlayerModelPanel->AddCarriedItem( pWeapon );
}
for ( int wbl = pPlayer->GetNumWearables()-1; wbl >= 0; wbl-- )
{
C_TFWearable *pItem = dynamic_cast<C_TFWearable*>( pPlayer->GetWearable( wbl ) );
if ( !pItem )
continue;
if ( pItem->IsViewModelWearable() )
continue;
if ( pItem->IsDisguiseWearable() && !bDisguised )
continue;
if ( !pItem->IsDisguiseWearable() && bDisguised )
continue;
CAttributeContainer *pCont = pItem->GetAttributeContainer();
CEconItemView *pEconItemView = pCont ? pCont->GetItem() : NULL;
if ( pEconItemView && pEconItemView->IsValid() )
{
m_pPlayerModelPanel->AddCarriedItem( pEconItemView );
}
}
m_pPlayerModelPanel->HoldItemInSlot( nItemSlot );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFHudPlayerClass::FireGameEvent( IGameEvent * event )
{
const char* pszEventName = event->GetName();
if ( FStrEq( "localplayer_changedisguise", pszEventName ) )
{
if ( m_pSpyImage && m_pSpyOutlineImage )
{
bool bFadeIn = event->GetBool( "disguised", false );
if ( bFadeIn )
{
m_pSpyImage->SetAlpha( 0 );
}
else
{
m_pSpyImage->SetAlpha( 255 );
}
m_pSpyOutlineImage->SetAlpha( 0 );
m_pSpyImage->SetVisible( true );
m_pSpyOutlineImage->SetVisible( true );
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( bFadeIn ? "HudSpyDisguiseFadeIn" : "HudSpyDisguiseFadeOut" );
}
UpdateModelPanel();
}
else if ( FStrEq( "post_inventory_application", pszEventName ) )
{
// Force a refresh. if this is for the local player
int iUserID = event->GetInt( "userid" );
C_TFPlayer* pPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
if ( pPlayer && pPlayer->GetUserID() == iUserID )
{
UpdateModelPanel();
}
}
else if ( FStrEq( "localplayer_pickup_weapon", pszEventName ) )
{
UpdateModelPanel();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFHealthPanel::CTFHealthPanel( Panel *parent, const char *name ) : vgui::Panel( parent, name )
{
m_flHealth = 1.0f;
m_iMaterialIndex = surface()->DrawGetTextureId( "hud/health_color" );
if ( m_iMaterialIndex == -1 ) // we didn't find it, so create a new one
{
m_iMaterialIndex = surface()->CreateNewTextureID();
surface()->DrawSetTextureFile( m_iMaterialIndex, "hud/health_color", true, false );
}
m_iDeadMaterialIndex = surface()->DrawGetTextureId( "hud/health_dead" );
if ( m_iDeadMaterialIndex == -1 ) // we didn't find it, so create a new one
{
m_iDeadMaterialIndex = surface()->CreateNewTextureID();
surface()->DrawSetTextureFile( m_iDeadMaterialIndex, "hud/health_dead", true, false );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFHealthPanel::Paint()
{
BaseClass::Paint();
int x, y, w, h;
GetBounds( x, y, w, h );
Vertex_t vert[4];
float uv1 = 0.0f;
float uv2 = 1.0f;
int xpos = 0, ypos = 0;
if ( m_flHealth <= 0 )
{
// Draw the dead material
surface()->DrawSetTexture( m_iDeadMaterialIndex );
vert[0].Init( Vector2D( xpos, ypos ), Vector2D( uv1, uv1 ) );
vert[1].Init( Vector2D( xpos + w, ypos ), Vector2D( uv2, uv1 ) );
vert[2].Init( Vector2D( xpos + w, ypos + h ), Vector2D( uv2, uv2 ) );
vert[3].Init( Vector2D( xpos, ypos + h ), Vector2D( uv1, uv2 ) );
surface()->DrawSetColor( Color(255,255,255,255) );
}
else
{
float flDamageY = h * ( 1.0f - m_flHealth );
// blend in the red "damage" part
surface()->DrawSetTexture( m_iMaterialIndex );
Vector2D uv11( uv1, uv2 - m_flHealth );
Vector2D uv21( uv2, uv2 - m_flHealth );
Vector2D uv22( uv2, uv2 );
Vector2D uv12( uv1, uv2 );
vert[0].Init( Vector2D( xpos, flDamageY ), uv11 );
vert[1].Init( Vector2D( xpos + w, flDamageY ), uv21 );
vert[2].Init( Vector2D( xpos + w, ypos + h ), uv22 );
vert[3].Init( Vector2D( xpos, ypos + h ), uv12 );
surface()->DrawSetColor( GetFgColor() );
}
surface()->DrawTexturedPolygon( 4, vert );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFHudPlayerHealth::CTFHudPlayerHealth( Panel *parent, const char *name ) : EditablePanel( parent, name )
{
m_pHealthImage = new CTFHealthPanel( this, "PlayerStatusHealthImage" );
m_pHealthImageBG = new ImagePanel( this, "PlayerStatusHealthImageBG" );
m_pHealthBonusImage = new ImagePanel( this, "PlayerStatusHealthBonusImage" );
m_pBuildingHealthImageBG = new ImagePanel( this, "BuildingStatusHealthImageBG" );
m_pBleedImage = new ImagePanel( this, "PlayerStatusBleedImage" );
m_pHookBleedImage = new ImagePanel( this, "PlayerStatusHookBleedImage" );
m_pMarkedForDeathImage = new ImagePanel( this, "PlayerStatusMarkedForDeathImage" );
m_pMarkedForDeathImageSilent = new ImagePanel( this, "PlayerStatusMarkedForDeathSilentImage" );
m_pMilkImage = new ImagePanel( this, "PlayerStatusMilkImage" );
m_pWheelOfDoomImage = new ImagePanel( this, "PlayerStatus_WheelOfDoom" );
m_flNextThink = 0.0f;
m_nBonusHealthOrigX = -1;
m_nBonusHealthOrigY = -1;
m_nBonusHealthOrigW = -1;
m_nBonusHealthOrigH = -1;
// Vaccinator
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_MEDIGUN_UBER_BULLET_RESIST, BUFF_CLASS_BULLET_RESIST, new ImagePanel( this, "PlayerStatus_MedicUberBulletResistImage" ), "../HUD/defense_buff_bullet_blue", "../HUD/defense_buff_bullet_red" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_MEDIGUN_UBER_BLAST_RESIST, BUFF_CLASS_BLAST_RESIST, new ImagePanel( this, "PlayerStatus_MedicUberBlastResistImage" ), "../HUD/defense_buff_explosion_blue", "../HUD/defense_buff_explosion_red" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_MEDIGUN_UBER_FIRE_RESIST, BUFF_CLASS_FIRE_RESIST, new ImagePanel( this, "PlayerStatus_MedicUberFireResistImage" ), "../HUD/defense_buff_fire_blue", "../HUD/defense_buff_fire_red" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_MEDIGUN_SMALL_BULLET_RESIST, BUFF_CLASS_BULLET_RESIST, new ImagePanel( this, "PlayerStatus_MedicSmallBulletResistImage" ), "../HUD/defense_buff_bullet_blue", "../HUD/defense_buff_bullet_red" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_MEDIGUN_SMALL_BLAST_RESIST, BUFF_CLASS_BLAST_RESIST, new ImagePanel( this, "PlayerStatus_MedicSmallBlastResistImage" ), "../HUD/defense_buff_explosion_blue", "../HUD/defense_buff_explosion_red" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_MEDIGUN_SMALL_FIRE_RESIST, BUFF_CLASS_FIRE_RESIST, new ImagePanel( this, "PlayerStatus_MedicSmallFireResistImage" ), "../HUD/defense_buff_fire_blue", "../HUD/defense_buff_fire_red" ) );
// Soldier buffs
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_OFFENSEBUFF, BUFF_CLASS_SOLDIER_OFFENSE, new ImagePanel( this, "PlayerStatus_SoldierOffenseBuff" ), "../Effects/soldier_buff_offense_blue", "../Effects/soldier_buff_offense_red" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_DEFENSEBUFF, BUFF_CLASS_SOLDIER_DEFENSE, new ImagePanel( this, "PlayerStatus_SoldierDefenseBuff" ), "../Effects/soldier_buff_defense_blue", "../Effects/soldier_buff_defense_red" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_REGENONDAMAGEBUFF, BUFF_CLASS_SOLDIER_HEALTHONHIT, new ImagePanel( this, "PlayerStatus_SoldierHealOnHitBuff" ), "../Effects/soldier_buff_healonhit_blue", "../Effects/soldier_buff_healonhit_red" ) );
// Powerup Rune status
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_STRENGTH, RUNE_CLASS_STRENGTH, new ImagePanel( this, "PlayerStatus_RuneStrength" ), "../Effects/powerup_strength_hud", "../Effects/powerup_strength_hud" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_HASTE, RUNE_CLASS_HASTE, new ImagePanel( this, "PlayerStatus_RuneHaste" ), "../Effects/powerup_haste_hud", "../Effects/powerup_haste_hud" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_REGEN, RUNE_CLASS_REGEN, new ImagePanel( this, "PlayerStatus_RuneRegen" ), "../Effects/powerup_regen_hud", "../Effects/powerup_regen_hud" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_RESIST, RUNE_CLASS_RESIST, new ImagePanel( this, "PlayerStatus_RuneResist" ), "../Effects/powerup_resist_hud", "../Effects/powerup_resist_hud" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_VAMPIRE, RUNE_CLASS_VAMPIRE, new ImagePanel( this, "PlayerStatus_RuneVampire" ), "../Effects/powerup_vampire_hud", "../Effects/powerup_vampire_hud" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_REFLECT, RUNE_CLASS_REFLECT, new ImagePanel( this, "PlayerStatus_RuneReflect" ), "../Effects/powerup_reflect_hud", "../Effects/powerup_reflect_hud" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_PRECISION, RUNE_CLASS_PRECISION, new ImagePanel( this, "PlayerStatus_RunePrecision" ), "../Effects/powerup_precision_hud", "../Effects/powerup_precision_hud" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_AGILITY, RUNE_CLASS_AGILITY, new ImagePanel( this, "PlayerStatus_RuneAgility" ), "../Effects/powerup_agility_hud", "../Effects/powerup_agility_hud" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_KNOCKOUT, RUNE_CLASS_KNOCKOUT, new ImagePanel( this, "PlayerStatus_RuneKnockout" ), "../Effects/powerup_knockout_hud", "../Effects/powerup_knockout_hud" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_KING, RUNE_CLASS_KING, new ImagePanel( this, "PlayerStatus_RuneKing" ), "../Effects/powerup_king_hud", "../Effects/powerup_king_hud" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_PLAGUE, RUNE_CLASS_PLAGUE, new ImagePanel( this, "PlayerStatus_RunePlague" ), "../Effects/powerup_plague_hud", "../Effects/powerup_plague_hud" ) );
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_SUPERNOVA, RUNE_CLASS_SUPERNOVA, new ImagePanel( this, "PlayerStatus_RuneSupernova" ), "../Effects/powerup_supernova_hud", "../Effects/powerup_supernova_hud" ) );
#ifdef STAGING_ONLY
// Spy Mark
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_TRANQ_MARKED, DEBUFF_CLASS_SPY_MARKED, new ImagePanel( this, "PlayerStatus_SpyMarked" ), "../Effects/tranq_debuff", "../Effects/tranq_debuff" ) );
#endif // STAGING_ONLY
// Parachute
m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_PARACHUTE_DEPLOYED, BUFF_CLASS_PARACHUTE, new ImagePanel( this, "PlayerStatus_Parachute" ), "../HUD/hud_parachute_active", "../HUD/hud_parachute_active" ) );
m_iAnimState = HUD_HEALTH_NO_ANIM;
m_bAnimate = true;
}
CTFHudPlayerHealth::~CTFHudPlayerHealth()
{
m_vecBuffInfo.PurgeAndDeleteElements();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFHudPlayerHealth::Reset()
{
m_flNextThink = gpGlobals->curtime + 0.05f;
m_nHealth = -1;
m_bBuilding = false;
m_iAnimState = HUD_HEALTH_NO_ANIM;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFHudPlayerHealth::ApplySchemeSettings( IScheme *pScheme )
{
// load control settings...
LoadControlSettings( GetResFilename() );
if ( m_pHealthBonusImage )
{
m_pHealthBonusImage->GetBounds( m_nBonusHealthOrigX, m_nBonusHealthOrigY, m_nBonusHealthOrigW, m_nBonusHealthOrigH );
}
m_flNextThink = 0.0f;
BaseClass::ApplySchemeSettings( pScheme );
m_pBuildingHealthImageBG->SetVisible( m_bBuilding );
m_pPlayerLevelLabel = dynamic_cast<CExLabel*>( FindChildByName( "PlayerStatusPlayerLevel" ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFHudPlayerHealth::SetHealth( int iNewHealth, int iMaxHealth, int iMaxBuffedHealth )
{
// set our health
m_nHealth = iNewHealth;
m_nMaxHealth = iMaxHealth;
m_pHealthImage->SetHealth( (float)(m_nHealth) / (float)(m_nMaxHealth) );
if ( m_pHealthImage )
{
m_pHealthImage->SetFgColor( Color( 255, 255, 255, 255 ) );
}
if ( m_nHealth <= 0 )
{
if ( m_pHealthImageBG->IsVisible() )
{
m_pHealthImageBG->SetVisible( false );
}
if ( m_pBuildingHealthImageBG->IsVisible() )
{
m_pBuildingHealthImageBG->SetVisible( false );
}
HideHealthBonusImage();
}
else
{
if ( !m_pHealthImageBG->IsVisible() )
{
m_pHealthImageBG->SetVisible( true );
}
m_pBuildingHealthImageBG->SetVisible( m_bBuilding );
// are we getting a health bonus?
if ( m_nHealth > m_nMaxHealth )
{
if ( m_pHealthBonusImage && m_nBonusHealthOrigW != -1 )
{
if ( !m_pHealthBonusImage->IsVisible() )
{
m_pHealthBonusImage->SetVisible( true );
}
if ( m_bAnimate && m_iAnimState != HUD_HEALTH_BONUS_ANIM )
{
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudHealthDyingPulseStop" );
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudHealthBonusPulse" );
m_iAnimState = HUD_HEALTH_BONUS_ANIM;
}
m_pHealthBonusImage->SetDrawColor( Color( 255, 255, 255, 255 ) );
// scale the flashing image based on how much health bonus we currently have
float flBoostMaxAmount = ( iMaxBuffedHealth ) - m_nMaxHealth;
float flPercent = MIN( ( m_nHealth - m_nMaxHealth ) / flBoostMaxAmount, 1.0f );
int nPosAdj = RoundFloatToInt( flPercent * m_nHealthBonusPosAdj );
int nSizeAdj = 2 * nPosAdj;
m_pHealthBonusImage->SetBounds( m_nBonusHealthOrigX - nPosAdj,
m_nBonusHealthOrigY - nPosAdj,
m_nBonusHealthOrigW + nSizeAdj,
m_nBonusHealthOrigH + nSizeAdj );
}
}
// are we close to dying?
else if ( m_nHealth < m_nMaxHealth * m_flHealthDeathWarning )
{
if ( m_pHealthBonusImage && m_nBonusHealthOrigW != -1 )
{
if ( !m_pHealthBonusImage->IsVisible() )
{
m_pHealthBonusImage->SetVisible( true );
}
if ( m_bAnimate && m_iAnimState != HUD_HEALTH_DYING_ANIM )
{
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudHealthBonusPulseStop" );
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudHealthDyingPulse" );
m_iAnimState = HUD_HEALTH_DYING_ANIM;
}
m_pHealthBonusImage->SetDrawColor( m_clrHealthDeathWarningColor );
// scale the flashing image based on how much health bonus we currently have
float flBoostMaxAmount = m_nMaxHealth * m_flHealthDeathWarning;
float flPercent = ( flBoostMaxAmount - m_nHealth ) / flBoostMaxAmount;
int nPosAdj = RoundFloatToInt( flPercent * m_nHealthBonusPosAdj );
int nSizeAdj = 2 * nPosAdj;
m_pHealthBonusImage->SetBounds( m_nBonusHealthOrigX - nPosAdj,
m_nBonusHealthOrigY - nPosAdj,
m_nBonusHealthOrigW + nSizeAdj,
m_nBonusHealthOrigH + nSizeAdj );
}
if ( m_pHealthImage )
{
m_pHealthImage->SetFgColor( m_clrHealthDeathWarningColor );
}
}
// turn it off
else
{
HideHealthBonusImage();
}
}
// set our health display value
if ( m_nHealth > 0 )
{
SetDialogVariable( "Health", m_nHealth );
}
else
{
SetDialogVariable( "Health", "" );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFHudPlayerHealth::SetLevel( int nLevel )
{
if ( m_pPlayerLevelLabel )
{
bool bVisible = ( nLevel >= 0 ) ? true : false;
if ( bVisible )
{
m_pPlayerLevelLabel->SetText( CFmtStr( "%d", nLevel ) );
}
if ( m_pPlayerLevelLabel->IsVisible() != bVisible )
{
m_pPlayerLevelLabel->SetVisible( bVisible );
}
}
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFHudPlayerHealth::HideHealthBonusImage( void )
{
if ( m_pHealthBonusImage && m_pHealthBonusImage->IsVisible() )
{
if ( m_nBonusHealthOrigW != -1 )
{
m_pHealthBonusImage->SetBounds( m_nBonusHealthOrigX, m_nBonusHealthOrigY, m_nBonusHealthOrigW, m_nBonusHealthOrigH );
}
m_pHealthBonusImage->SetVisible( false );
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudHealthBonusPulseStop" );
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudHealthDyingPulseStop" );
m_iAnimState = HUD_HEALTH_NO_ANIM;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
static void SetPlayerHealthImagePanelVisibility( CTFPlayer *pPlayer, ETFCond eCond, vgui::ImagePanel *pImagePanel, int& nXOffset, const Color& colorIfVisible )
{
Assert( pImagePanel != NULL );
if ( pPlayer->m_Shared.InCond( eCond ) && !pImagePanel->IsVisible() )
{
pImagePanel->SetVisible( true );
pImagePanel->SetDrawColor( colorIfVisible );
// Reposition ourselves and increase the offset if we are active
int x,y;
pImagePanel->GetPos( x, y );
pImagePanel->SetPos( nXOffset, y );
nXOffset += 100.f;
}
}
void CTFBuffInfo::Update( CTFPlayer *pPlayer )
{
Assert( m_pImagePanel != NULL && pPlayer != NULL );
if ( pPlayer->m_Shared.InCond( m_eCond ) )
{
if( m_pzsBlueImage && m_pzsBlueImage[0] && m_pzsRedImage && m_pzsRedImage[0] )
{
if( pPlayer->GetTeamNumber() == TF_TEAM_BLUE )
m_pImagePanel->SetImage( m_pzsBlueImage );
else
m_pImagePanel->SetImage( m_pzsRedImage );
}
}
}
void CTFHudPlayerHealth::OnThink()
{
if ( m_flNextThink < gpGlobals->curtime )
{
C_TFPlayer *pPlayer = ToTFPlayer( C_BasePlayer::GetLocalPlayer() );
if ( pPlayer )
{
SetHealth( pPlayer->GetHealth(), pPlayer->GetMaxHealth(), pPlayer->m_Shared.GetMaxBuffedHealth() );
int color_offset = ((int)(gpGlobals->realtime*10)) % 5;
int color_fade = 160 + (color_offset*10);
// Find our starting point, just above the health '+'
int nXOffset,y;
m_pHealthImage->GetPos( nXOffset, y );
// Nudge over a bit to get centered
nXOffset += 25;
// Turn all the panels off, and below conditionally turn them on
FOR_EACH_VEC( m_vecBuffInfo, i )
{
m_vecBuffInfo[ i ]->m_pImagePanel->SetVisible( false );
}
CUtlVector<BuffClass_t> m_vecActiveClasses;
// Cycle through all the buffs and update them
FOR_EACH_VEC( m_vecBuffInfo, i )
{
// Skip if this class of buff is already being drawn
if( m_vecActiveClasses.Find( m_vecBuffInfo[i]->m_eClass ) != m_vecActiveClasses.InvalidIndex() )
continue;
m_vecBuffInfo[i]->Update( pPlayer );
SetPlayerHealthImagePanelVisibility( pPlayer, m_vecBuffInfo[i]->m_eCond, m_vecBuffInfo[i]->m_pImagePanel, nXOffset, Color( 255, 255, 255, color_fade ) );
// This class of buff is now active.
if( m_vecBuffInfo[i]->m_pImagePanel->IsVisible() )
{
m_vecActiveClasses.AddToTail( m_vecBuffInfo[i]->m_eClass );
}
}
// Turn all the panels off, and below conditionally turn them on
m_pBleedImage->SetVisible( false );
m_pHookBleedImage->SetVisible( false );
m_pMilkImage->SetVisible( false );
m_pMarkedForDeathImage->SetVisible( false );
m_pMarkedForDeathImageSilent->SetVisible( false );
// Old method for goofy color manipulation
int nBloodX = nXOffset;
SetPlayerHealthImagePanelVisibility( pPlayer, TF_COND_BLEEDING, m_pBleedImage, nXOffset, Color( color_fade, 0, 0, 255 ) );
SetPlayerHealthImagePanelVisibility( pPlayer, TF_COND_GRAPPLINGHOOK_BLEEDING, m_pHookBleedImage, nBloodX, Color( 255, 255, 255, 255 ) ); // draw this on top of bleeding
SetPlayerHealthImagePanelVisibility( pPlayer, TF_COND_MAD_MILK, m_pMilkImage, nXOffset, Color( color_fade, color_fade, color_fade, 255 ) );
SetPlayerHealthImagePanelVisibility( pPlayer, TF_COND_MARKEDFORDEATH, m_pMarkedForDeathImage, nXOffset, Color( 255 - color_fade, 245 - color_fade, 245 - color_fade, 255 ) );
SetPlayerHealthImagePanelVisibility( pPlayer, TF_COND_MARKEDFORDEATH_SILENT, m_pMarkedForDeathImageSilent, nXOffset, Color( 125 - color_fade, 255 - color_fade, 255 - color_fade, 255 ) );
SetPlayerHealthImagePanelVisibility( pPlayer, TF_COND_PASSTIME_PENALTY_DEBUFF, m_pMarkedForDeathImageSilent, nXOffset, Color( 125 - color_fade, 255 - color_fade, 255 - color_fade, 255 ) );
UpdateHalloweenStatus();
}
m_flNextThink = gpGlobals->curtime + 0.05f;
}
}
void CTFHudPlayerHealth::UpdateHalloweenStatus( void )
{
if ( TFGameRules()->IsHalloweenEffectStatusActive() )
{
int status = TFGameRules()->GetHalloweenEffectStatus();
if ( status == EFFECT_WHAMMY )
{
m_pWheelOfDoomImage->SetImage( "..\\HUD\\death_wheel_whammy" );
}
else
{
m_pWheelOfDoomImage->SetImage( VarArgs( "..\\HUD\\death_wheel_%d", status - 1 ) );
}
float timeLeft = TFGameRules()->GetHalloweenEffectTimeLeft();
const float warnExpireTime = 3.0f;
const float blinkInterval = 0.25f;
if ( timeLeft < warnExpireTime )
{
int blink = (int)( timeLeft / blinkInterval );
m_pWheelOfDoomImage->SetVisible( blink & 0x1 );
}
else
{
m_pWheelOfDoomImage->SetVisible( true );
}
}
else
{
m_pWheelOfDoomImage->SetVisible( false );
}
}
DECLARE_HUDELEMENT( CTFHudPlayerStatus );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFHudPlayerStatus::CTFHudPlayerStatus( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "HudPlayerStatus" )
{
Panel *pParent = g_pClientMode->GetViewport();
SetParent( pParent );
m_pHudPlayerClass = new CTFHudPlayerClass( this, "HudPlayerClass" );
m_pHudPlayerHealth = new CTFHudPlayerHealth( this, "HudPlayerHealth" );
SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFHudPlayerStatus::ApplySchemeSettings( IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
// HACK: Work around the scheme application order failing
// to reload the player class hud element's scheme in minmode.
static ConVarRef cl_hud_minmode( "cl_hud_minmode", true );
if ( cl_hud_minmode.IsValid() && cl_hud_minmode.GetBool() )
{
m_pHudPlayerClass->InvalidateLayout( false, true );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTFHudPlayerStatus::ShouldDraw( void )
{
CTFPlayer *pTFPlayer = CTFPlayer::GetLocalTFPlayer();
if ( pTFPlayer && pTFPlayer->m_Shared.InCond( TF_COND_HALLOWEEN_GHOST_MODE ) )
return false;
if ( CTFMinigameLogic::GetMinigameLogic() && CTFMinigameLogic::GetMinigameLogic()->GetActiveMinigame() )
return false;
if ( TFGameRules() && TFGameRules()->ShowMatchSummary() )
return false;
return CHudElement::ShouldDraw();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFHudPlayerStatus::Reset()
{
if ( m_pHudPlayerClass )
{
m_pHudPlayerClass->Reset();
}
if ( m_pHudPlayerHealth )
{
m_pHudPlayerHealth->Reset();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFClassImage::SetClass( int iTeam, int iClass, int iCloakstate )
{
char szImage[128];
szImage[0] = '\0';
if ( iTeam == TF_TEAM_BLUE )
{
Q_strncpy( szImage, g_szBlueClassImages[ iClass ], sizeof(szImage) );
}
else
{
Q_strncpy( szImage, g_szRedClassImages[ iClass ], sizeof(szImage) );
}
switch( iCloakstate )
{
case 2:
Q_strncat( szImage, "_cloak", sizeof(szImage), COPY_ALL_CHARACTERS );
break;
case 1:
Q_strncat( szImage, "_halfcloak", sizeof(szImage), COPY_ALL_CHARACTERS );
break;
default:
break;
}
if ( Q_strlen( szImage ) > 0 )
{
SetImage( szImage );
}
}