//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CSecondaryTargetID::CalculateTargetIndex( C_TFPlayer *pLocalTFPlayer ) { // If we're a medic & we're healing someone, target him. CBaseEntity *pHealTarget = pLocalTFPlayer->MedicGetHealTarget(); if ( pHealTarget ) { if ( pHealTarget->entindex() != m_iTargetEntIndex ) { g_pVGuiLocalize->ConstructString( m_wszPrepend, sizeof(m_wszPrepend), g_pVGuiLocalize->Find("#TF_playerid_healtarget" ), 0 ); } return pHealTarget->entindex(); } // If we have a healer, target him. C_TFPlayer *pHealer; float flHealerChargeLevel; pLocalTFPlayer->GetHealer( &pHealer, &flHealerChargeLevel ); if ( pHealer ) { if ( pHealer->entindex() != m_iTargetEntIndex ) { g_pVGuiLocalize->ConstructString( m_wszPrepend, sizeof(m_wszPrepend), g_pVGuiLocalize->Find("#TF_playerid_healer" ), 0 ); } return pHealer->entindex(); } if ( m_iTargetEntIndex ) { m_wszPrepend[0] = '\0'; } return 0; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void DispatchParticleEffect( int iEffectIndex, Vector vecOrigin, Vector vecStart, QAngle vecAngles, CBaseEntity *pEntity ) { CEffectData data; data.m_nHitBox = iEffectIndex; data.m_vOrigin = vecOrigin; data.m_vStart = vecStart; data.m_vAngles = vecAngles; if ( pEntity ) { #ifdef CLIENT_DLL data.m_hEntity = pEntity; #else data.m_nEntIndex = pEntity->entindex(); #endif data.m_fFlags |= PARTICLE_DISPATCH_FROM_ENTITY; data.m_nDamageType = PATTACH_CUSTOMORIGIN; #if defined(TF_CLASSIC_CLIENT) if (TFGameRules() && TFGameRules()->IsDeathmatch()) { C_TFPlayer *pPlayer = ToTFPlayer(pEntity); if (pPlayer && pPlayer->m_Shared.InCond(TF_COND_POWERUP_CRITDAMAGE)) { data.m_bCustomColors = true; C_TF_PlayerResource *pResource = dynamic_cast<C_TF_PlayerResource *>(g_PR); data.m_CustomColors.m_vecColor1 = Vector( pResource->GetPlayerColor(pPlayer->entindex()).r() / 255.0f, pResource->GetPlayerColor(pPlayer->entindex()).g() / 255.0f, pResource->GetPlayerColor(pPlayer->entindex()).b() / 255.0f ); } } #endif } else { #ifdef CLIENT_DLL data.m_hEntity = NULL; #else data.m_nEntIndex = 0; #endif } DispatchEffect( "ParticleEffect", data ); }
//----------------------------------------------------------------------------- // Purpose: Updates details about a player //----------------------------------------------------------------------------- void CTFDeathMatchScoreBoardDialog::UpdatePlayerDetails() { ClearPlayerDetails(); C_TF_PlayerResource *tf_PR = dynamic_cast<C_TF_PlayerResource *>( g_PR ); if ( !tf_PR ) return; C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); if ( !pLocalPlayer ) return; int playerIndex = pLocalPlayer->entindex(); // Make sure the selected player is still connected. if ( !tf_PR->IsConnected( playerIndex ) ) return; if ( engine->IsHLTV() ) { SetDialogVariable( "playername", tf_PR->GetPlayerName( playerIndex ) ); return; } RoundStats_t &roundStats = GetStatPanel()->GetRoundStatsCurrentGame(); SetDialogVariable( "kills", tf_PR->GetPlayerScore( playerIndex ) ); SetDialogVariable( "deaths", tf_PR->GetDeaths( playerIndex ) ); SetDialogVariable("assists", roundStats.m_iStat[TFSTAT_KILLASSISTS]); SetDialogVariable("dominations", roundStats.m_iStat[TFSTAT_DOMINATIONS]); SetDialogVariable("revenge", roundStats.m_iStat[TFSTAT_REVENGE]); SetDialogVariable( "playername", tf_PR->GetPlayerName( playerIndex ) ); SetDialogVariable( "playerscore", GetPointsString( tf_PR->GetTotalScore( playerIndex ) ) ); Color clr = tf_PR->GetPlayerColor(playerIndex); m_pRedScoreBG->SetFillColor(clr); }
//----------------------------------------------------------------------------- // Purpose: This runs on both the client and the server. On the server, it // only does the damage calculations. On the client, it does all the effects. //----------------------------------------------------------------------------- void FX_FireBullets( int iPlayer, const Vector &vecOrigin, const QAngle &vecAngles, int iWeapon, int iMode, int iSeed, float flSpread, float flDamage /* = -1.0f */, bool bCritical /* = false*/ ) { // Get the weapon information. const char *pszWeaponAlias = WeaponIdToAlias( iWeapon ); if ( !pszWeaponAlias ) { DevMsg( 1, "FX_FireBullets: weapon alias for ID %i not found\n", iWeapon ); return; } WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( pszWeaponAlias ); if ( hWpnInfo == GetInvalidWeaponInfoHandle() ) { DevMsg( 1, "FX_FireBullets: LookupWeaponInfoSlot failed for weapon %s\n", pszWeaponAlias ); return; } CTFWeaponInfo *pWeaponInfo = static_cast<CTFWeaponInfo*>( GetFileWeaponInfoFromHandle( hWpnInfo ) ); if( !pWeaponInfo ) return; bool bDoEffects = false; #ifdef CLIENT_DLL C_TFPlayer *pPlayer = ToTFPlayer( ClientEntityList().GetBaseEntity( iPlayer ) ); #else CTFPlayer *pPlayer = ToTFPlayer( UTIL_PlayerByIndex( iPlayer ) ); #endif if ( !pPlayer ) return; // Client specific. #ifdef CLIENT_DLL bDoEffects = true; // The minigun has custom sound & animation code to deal with its windup/down. if ( !pPlayer->IsLocalPlayer() && iWeapon != TF_WEAPON_MINIGUN ) { // Fire the animation event. if ( pPlayer && !pPlayer->IsDormant() ) { if ( iMode == TF_WEAPON_PRIMARY_MODE ) { pPlayer->m_PlayerAnimState->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_PRIMARY ); } else { pPlayer->m_PlayerAnimState->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_SECONDARY ); } } //FX_WeaponSound( pPlayer->entindex(), SINGLE, vecOrigin, pWeaponInfo ); } // Server specific. #else // If this is server code, send the effect over to client as temp entity and // dispatch one message for all the bullet impacts and sounds. TE_FireBullets( pPlayer->entindex(), vecOrigin, vecAngles, iWeapon, iMode, iSeed, flSpread, bCritical ); // Let the player remember the usercmd he fired a weapon on. Assists in making decisions about lag compensation. pPlayer->NoteWeaponFired(); #endif // Fire bullets, calculate impacts & effects. StartGroupingSounds(); #if !defined (CLIENT_DLL) // Move other players back to history positions based on local player's lag lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() ); #endif // Get the shooting angles. Vector vecShootForward, vecShootRight, vecShootUp; AngleVectors( vecAngles, &vecShootForward, &vecShootRight, &vecShootUp ); // Initialize the static firing information. FireBulletsInfo_t fireInfo; fireInfo.m_vecSrc = vecOrigin; if ( flDamage < 0.0f ) { fireInfo.m_flDamage = pWeaponInfo->GetWeaponData( iMode ).m_nDamage; } else { fireInfo.m_flDamage = static_cast<int>(flDamage); } fireInfo.m_flDistance = pWeaponInfo->GetWeaponData( iMode ).m_flRange; fireInfo.m_iShots = 1; fireInfo.m_vecSpread.Init( flSpread, flSpread, 0.0f ); fireInfo.m_iAmmoType = pWeaponInfo->iAmmoType; // Setup the bullet damage type & roll for crit. int nDamageType = DMG_GENERIC; int nCustomDamageType = TF_DMG_CUSTOM_NONE; CTFWeaponBase *pWeapon = pPlayer->GetActiveTFWeapon(); if ( pWeapon ) { nDamageType = pWeapon->GetDamageType(); if ( pWeapon->IsCurrentAttackACrit() || bCritical ) { nDamageType |= DMG_CRITICAL; } nCustomDamageType = pWeapon->GetCustomDamageType(); } if ( iWeapon != TF_WEAPON_MINIGUN ) { fireInfo.m_iTracerFreq = 2; } // Reset multi-damage structures. ClearMultiDamage(); int nBulletsPerShot = pWeaponInfo->GetWeaponData( iMode ).m_nBulletsPerShot; for ( int iBullet = 0; iBullet < nBulletsPerShot; ++iBullet ) { // Initialize random system with this seed. RandomSeed( iSeed ); // Determine if the first bullet should be perfectly accurate. bool bPerfectAccuracy = false; if ( pWeapon && iBullet == 0 ) { float flFireInterval = gpGlobals->curtime - pWeapon->GetLastFireTime(); if ( nBulletsPerShot == 1 ) bPerfectAccuracy = flFireInterval > 1.25f; else bPerfectAccuracy = flFireInterval > 0.25f; } float x = 0.0f; float y = 0.0f; // tf_use_fixed_weapon_spread calculations go here. if ( !bPerfectAccuracy ) { // Get circular gaussian spread. x = RandomFloat( -0.5, 0.5 ) + RandomFloat( -0.5, 0.5 ); y = RandomFloat( -0.5, 0.5 ) + RandomFloat( -0.5, 0.5 ); } // Initialize the varialbe firing information. fireInfo.m_vecDirShooting = vecShootForward + ( x * flSpread * vecShootRight ) + ( y * flSpread * vecShootUp ); fireInfo.m_vecDirShooting.NormalizeInPlace(); // Fire a bullet. pPlayer->FireBullet( fireInfo, bDoEffects, nDamageType, nCustomDamageType ); // Use new seed for next bullet. ++iSeed; } // Apply damage if any. ApplyMultiDamage(); #if !defined (CLIENT_DLL) lagcompensation->FinishLagCompensation( pPlayer ); #endif EndGroupingSounds(); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFreezePanel::FireGameEvent( IGameEvent * event ) { const char *pEventName = event->GetName(); if ( Q_strcmp( "player_death", pEventName ) == 0 ) { // see if the local player died int iPlayerIndexVictim = engine->GetPlayerForUserID( event->GetInt( "userid" ) ); C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); if ( pLocalPlayer && iPlayerIndexVictim == pLocalPlayer->entindex() ) { // the local player is dead, see if this is a new nemesis or a revenge if ( event->GetInt( "dominated" ) > 0 ) { m_iShowNemesisPanel = SHOW_NEW_NEMESIS; } else if ( event->GetInt( "revenge" ) > 0 ) { m_iShowNemesisPanel = SHOW_REVENGE; } else { m_iShowNemesisPanel = SHOW_NO_NEMESIS; } } } else if ( Q_strcmp( "hide_freezepanel", pEventName ) == 0 ) { Hide(); } else if ( Q_strcmp( "freezecam_started", pEventName ) == 0 ) { ShowCalloutsIn( 1.0 ); ShowSnapshotPanelIn( 1.25 ); } else if ( Q_strcmp( "teamplay_win_panel", pEventName ) == 0 ) { Hide(); } else if ( Q_strcmp( "show_freezepanel", pEventName ) == 0 ) { C_TF_PlayerResource *tf_PR = dynamic_cast<C_TF_PlayerResource *>(g_PR); if ( !tf_PR ) { m_pNemesisSubPanel->SetDialogVariable( "nemesisname", NULL ); return; } Show(); ShowSnapshotPanel( false ); m_bHoldingAfterScreenshot = false; if ( m_iBasePanelOriginalX > -1 && m_iBasePanelOriginalY > -1 ) { m_pBasePanel->SetPos( m_iBasePanelOriginalX, m_iBasePanelOriginalY ); } // Get the entity who killed us m_iKillerIndex = event->GetInt( "killer" ); C_BaseEntity *pKiller = ClientEntityList().GetBaseEntity( m_iKillerIndex ); int xp,yp; GetPos( xp, yp ); if ( TFGameRules()->RoundHasBeenWon() ) { SetPos( xp, m_iYBase - YRES(50) ); } else { SetPos( xp, m_iYBase ); } if ( pKiller ) { CTFPlayer *pPlayer = ToTFPlayer ( pKiller ); int iMaxBuffedHealth = 0; if ( pPlayer ) { iMaxBuffedHealth = pPlayer->m_Shared.GetMaxBuffedHealth(); } int iKillerHealth = pKiller->GetHealth(); if ( !pKiller->IsAlive() ) { iKillerHealth = 0; } m_pKillerHealth->SetHealth( iKillerHealth, pKiller->GetMaxHealth(), iMaxBuffedHealth ); if ( pKiller->IsPlayer() ) { C_TFPlayer *pVictim = C_TFPlayer::GetLocalTFPlayer(); CTFPlayer *pTFKiller = ToTFPlayer( pKiller ); //If this was just a regular kill but this guy is our nemesis then just show it. if ( pVictim && pTFKiller && pTFKiller->m_Shared.IsPlayerDominated( pVictim->entindex() ) ) { if ( !pKiller->IsAlive() ) { m_pFreezeLabel->SetText( "#FreezePanel_Nemesis_Dead" ); } else { m_pFreezeLabel->SetText( "#FreezePanel_Nemesis" ); } } else { if ( !pKiller->IsAlive() ) { m_pFreezeLabel->SetText( "#FreezePanel_Killer_Dead" ); } else { m_pFreezeLabel->SetText( "#FreezePanel_Killer" ); } } m_pBasePanel->SetDialogVariable( "killername", g_PR->GetPlayerName( m_iKillerIndex ) ); if ( m_pAvatar ) { m_pAvatar->SetPlayer( (C_BasePlayer*)pKiller ); } } else if ( pKiller->IsBaseObject() ) { C_BaseObject *pObj = assert_cast<C_BaseObject *>( pKiller ); C_TFPlayer *pOwner = pObj->GetOwner(); Assert( pOwner && "Why does this object not have an owner?" ); if ( pOwner ) { m_iKillerIndex = pOwner->entindex(); m_pBasePanel->SetDialogVariable( "killername", g_PR->GetPlayerName( m_iKillerIndex ) ); if ( m_pAvatar ) { m_pAvatar->SetPlayer( pOwner ); } pKiller = pOwner; } if ( m_pFreezeLabel ) { if ( pKiller && !pKiller->IsAlive() ) { m_pFreezeLabel->SetText( "#FreezePanel_KillerObject_Dead" ); } else { m_pFreezeLabel->SetText( "#FreezePanel_KillerObject" ); } } const char *pszStatusName = pObj->GetStatusName(); wchar_t *wszLocalized = g_pVGuiLocalize->Find( pszStatusName ); if ( !wszLocalized ) { m_pBasePanel->SetDialogVariable( "objectkiller", pszStatusName ); } else { m_pBasePanel->SetDialogVariable( "objectkiller", wszLocalized ); } } else if ( m_pFreezeLabel ) { if ( !pKiller->IsAlive() ) { m_pFreezeLabel->SetText( "#FreezePanel_Killer_Dead" ); } else { m_pFreezeLabel->SetText( "#FreezePanel_Killer" ); } } } // see if we should show nemesis panel const wchar_t *pchNemesisText = NULL; switch ( m_iShowNemesisPanel ) { case SHOW_NO_NEMESIS: { C_TFPlayer *pVictim = C_TFPlayer::GetLocalTFPlayer(); CTFPlayer *pTFKiller = ToTFPlayer( pKiller ); //If this was just a regular kill but this guy is our nemesis then just show it. if ( pTFKiller && pTFKiller->m_Shared.IsPlayerDominated( pVictim->entindex() ) ) { pchNemesisText = g_pVGuiLocalize->Find( "#TF_FreezeNemesis" ); } } break; case SHOW_NEW_NEMESIS: { C_TFPlayer *pVictim = C_TFPlayer::GetLocalTFPlayer(); CTFPlayer *pTFKiller = ToTFPlayer( pKiller ); // check to see if killer is still the nemesis of victim; victim may have managed to kill him after victim's // death by grenade or some such, extracting revenge and clearing nemesis condition if ( pTFKiller && pTFKiller->m_Shared.IsPlayerDominated( pVictim->entindex() ) ) { pchNemesisText = g_pVGuiLocalize->Find( "#TF_NewNemesis" ); } } break; case SHOW_REVENGE: pchNemesisText = g_pVGuiLocalize->Find( "#TF_GotRevenge" ); break; default: Assert( false ); // invalid value break; } m_pNemesisSubPanel->SetDialogVariable( "nemesisname", pchNemesisText ); ShowNemesisPanel( NULL != pchNemesisText ); m_iShowNemesisPanel = SHOW_NO_NEMESIS; } }
//----------------------------------------------------------------------------- // Purpose: Updates the player list //----------------------------------------------------------------------------- void CTFDeathMatchScoreBoardDialog::UpdatePlayerList() { int iSelectedPlayerIndex = GetLocalPlayerIndex(); // Save off which player we had selected SectionedListPanel *pList = GetSelectedPlayerList(); if ( pList ) { int itemID = pList->GetSelectedItem(); if ( itemID >= 0 ) { KeyValues *pInfo = pList->GetItemData( itemID ); if ( pInfo ) { iSelectedPlayerIndex = pInfo->GetInt( "playerIndex" ); } } } m_pPlayerListRed->RemoveAll(); C_TF_PlayerResource *tf_PR = dynamic_cast<C_TF_PlayerResource *>( g_PR ); if ( !tf_PR ) return; C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); if ( !pLocalPlayer ) return; int localteam = pLocalPlayer->GetTeamNumber(); bool bMadeSelection = false; for( int playerIndex = 1 ; playerIndex <= MAX_PLAYERS; playerIndex++ ) { if( g_PR->IsConnected( playerIndex ) ) { SectionedListPanel *pPlayerList = NULL; switch ( g_PR->GetTeam( playerIndex ) ) { case TF_TEAM_RED: pPlayerList = m_pPlayerListRed; break; } if ( null == pPlayerList ) continue; const char *szName = tf_PR->GetPlayerName(playerIndex); int score = tf_PR->GetTotalScore(playerIndex); int kills = tf_PR->GetPlayerScore(playerIndex); int deaths = tf_PR->GetDeaths(playerIndex); int streak = tf_PR->GetKillstreak(playerIndex); KeyValues *pKeyValues = new KeyValues( "data" ); pKeyValues->SetInt( "playerIndex", playerIndex ); pKeyValues->SetString( "name", szName ); pKeyValues->SetInt("score", score); pKeyValues->SetInt("kills", kills); pKeyValues->SetInt("deaths", deaths); pKeyValues->SetInt("streak", streak); // can only see class information if we're on the same team if ( !AreEnemyTeams( g_PR->GetTeam( playerIndex ), localteam ) && !( localteam == TEAM_UNASSIGNED ) ) { // class name if( g_PR->IsConnected( playerIndex ) ) { int iClass = tf_PR->GetPlayerClass( playerIndex ); if ( GetLocalPlayerIndex() == playerIndex && !tf_PR->IsAlive( playerIndex ) ) { // If this is local player and he is dead, show desired class (which he will spawn as) rather than current class. C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer(); int iDesiredClass = pPlayer->m_Shared.GetDesiredPlayerClassIndex(); // use desired class unless it's random -- if random, his future class is not decided until moment of spawn if ( TF_CLASS_RANDOM != iDesiredClass ) { iClass = iDesiredClass; } } else { // for non-local players, show the current class iClass = tf_PR->GetPlayerClass( playerIndex ); } } } else { C_TFPlayer *pPlayerOther = ToTFPlayer( UTIL_PlayerByIndex( playerIndex ) ); if ( pPlayerOther && pPlayerOther->m_Shared.IsPlayerDominated( pLocalPlayer->entindex() ) ) { // if local player is dominated by this player, show a nemesis icon pKeyValues->SetInt( "nemesis", m_iImageNemesis ); } else if ( pLocalPlayer->m_Shared.IsPlayerDominated( playerIndex) ) { // if this player is dominated by the local player, show the domination icon pKeyValues->SetInt( "nemesis", m_iImageDominated ); } } // display whether player is alive or dead (all players see this for all other players on both teams) pKeyValues->SetInt( "status", tf_PR->IsAlive( playerIndex ) ? 0 : m_iImageDead ); if ( g_PR->GetPing( playerIndex ) < 1 ) { if ( g_PR->IsFakePlayer( playerIndex ) ) { pKeyValues->SetString( "ping", "#TF_Scoreboard_Bot" ); } else { pKeyValues->SetString( "ping", "" ); } } else { pKeyValues->SetInt( "ping", g_PR->GetPing( playerIndex ) ); } UpdatePlayerAvatar( playerIndex, pKeyValues ); int itemID = pPlayerList->AddItem( 0, pKeyValues ); Color clr = tf_PR->GetPlayerColor(playerIndex); pPlayerList->SetItemFgColor( itemID, clr ); if ( iSelectedPlayerIndex == playerIndex ) { bMadeSelection = true; pPlayerList->SetSelectedItem( itemID ); } pKeyValues->deleteThis(); } } // If we're on spectator, find a default selection if ( !bMadeSelection ) { if ( m_pPlayerListRed->GetItemCount() > 0 ) { m_pPlayerListRed->SetSelectedItem( 0 ); } } ResizeScoreboard(); }