summaryrefslogtreecommitdiff
path: root/game/shared/tf/achievements_tf_spy.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/tf/achievements_tf_spy.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/shared/tf/achievements_tf_spy.cpp')
-rw-r--r--game/shared/tf/achievements_tf_spy.cpp1773
1 files changed, 1773 insertions, 0 deletions
diff --git a/game/shared/tf/achievements_tf_spy.cpp b/game/shared/tf/achievements_tf_spy.cpp
new file mode 100644
index 0000000..a13ae2e
--- /dev/null
+++ b/game/shared/tf/achievements_tf_spy.cpp
@@ -0,0 +1,1773 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+
+#include "cbase.h"
+
+#ifdef CLIENT_DLL
+
+#include "achievementmgr.h"
+#include "baseachievement.h"
+#include "tf_hud_statpanel.h"
+#include "c_tf_team.h"
+#include "c_tf_player.h"
+#include "c_tf_playerresource.h"
+#include "tf_gamerules.h"
+#include "achievements_tf.h"
+#include "c_tf_playerresource.h"
+#include "tf_weapon_invis.h"
+
+//======================================================================================================================================
+// SPY ACHIEVEMENT PACK
+//======================================================================================================================================
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyBackstabSnipers : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+ }
+
+ void ResetTracking()
+ {
+ m_iSnipersKilled = 0;
+ }
+
+ virtual void ListenForEvents( void )
+ {
+ ListenForGameEvent( "localplayer_respawn" );
+ ListenForGameEvent( "teamplay_round_active" );
+
+ ResetTracking();
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ const char *pszEventName = event->GetName();
+
+ if ( FStrEq( pszEventName, "localplayer_respawn" ) ||
+ FStrEq( pszEventName, "teamplay_round_active" ) )
+ {
+ ResetTracking();
+ }
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ // Achievement for backstabbing 3 snipers in a single life.
+ CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
+ if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SNIPER ) )
+ {
+ int customkill = event->GetInt( "customkill" );
+ if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
+ {
+ m_iSnipersKilled++;
+ if ( m_iSnipersKilled == 3 )
+ {
+ IncrementCount();
+ }
+ }
+ }
+ }
+
+ int m_iSnipersKilled;
+
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabSnipers, ACHIEVEMENT_TF_SPY_BACKSTAB_SNIPERS, "TF_SPY_BACKSTAB_SNIPERS", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_FreezecamFlick : public CBaseTFAchievement
+{
+ // Achievement for freeze camming on a cig flick w/ enemy corpse on screen.
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_FreezecamFlick, ACHIEVEMENT_TF_SPY_FREEZECAM_FLICK, "TF_SPY_FREEZECAM_FLICK", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyBackstabDisguisedSpy : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ // Achievement for backstabbing a disguised spy.
+ CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
+ if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SPY ) )
+ {
+ int customkill = event->GetInt( "customkill" );
+ if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
+ {
+ if ( pTFVictim->m_Shared.InCond( TF_COND_DISGUISED ) )
+ {
+ IncrementCount();
+ }
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabDisguisedSpy, ACHIEVEMENT_TF_SPY_BACKSTAB_DISGUISED_SPY, "TF_SPY_BACKSTAB_DISGUISED_SPY", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyBackstabDisguiseTarget : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ // Achievement for backstabbing the player you are disguised as.
+ CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
+ CTFPlayer *pTFAttacker = ToTFPlayer( pAttacker );
+ if ( pTFAttacker && pTFVictim && pTFVictim == pTFAttacker->m_Shared.GetDisguiseTarget().Get() )
+ {
+ int customkill = event->GetInt( "customkill" );
+ if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
+ {
+ IncrementCount();
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabDisguiseTarget, ACHIEVEMENT_TF_SPY_BACKSTAB_DISGUISE_TARGET, "TF_SPY_BACKSTAB_DISGUISE_TARGET", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyFastCap : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+ }
+
+ virtual void ListenForEvents( void )
+ {
+ ListenForGameEvent( "teamplay_point_startcapture" );
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ // only on maps with capture points
+ if ( TFGameRules() && TFGameRules()->GetGameType() != TF_GAMETYPE_CP && TFGameRules()->GetGameType() != TF_GAMETYPE_ARENA )
+ return;
+
+ const char *pszEventName = event->GetName();
+
+ CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
+ if ( !pLocalPlayer )
+ return;
+
+ if ( FStrEq( pszEventName, "teamplay_point_startcapture" ) )
+ {
+ const char *cappers = event->GetString( "cappers" );
+ for ( int i=0; i<Q_strlen( cappers ); i++ )
+ {
+ int iPlayerIndex = (int) cappers[i];
+ CTFPlayer *pPlayer = ToTFPlayer( UTIL_PlayerByIndex( iPlayerIndex ) );
+ if ( pPlayer == pLocalPlayer )
+ {
+ if ( event->GetFloat( "captime" ) < 1.0 )
+ {
+ IncrementCount();
+ }
+ }
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyFastCap, ACHIEVEMENT_TF_SPY_FAST_CAP, "TF_SPY_FAST_CAP", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyDominateSniper : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ bool bDomination = event->GetInt( "death_flags" ) & TF_DEATH_DOMINATION;
+
+ if ( bDomination == true )
+ {
+ CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
+
+ if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SNIPER ) )
+ {
+ IncrementCount();
+ }
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyDominateSniper, ACHIEVEMENT_TF_SPY_DOMINATE_SNIPER, "TF_SPY_DOMINATE_SNIPER", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyBumpCloakedSpy : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+ }
+
+ // server awards this achievement, no other code within achievement necessary
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBumpCloakedSpy, ACHIEVEMENT_TF_SPY_BUMP_CLOAKED_SPY, "TF_SPY_BUMP_CLOAKED_SPY", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyKillSpyWithKnife : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
+
+ if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SPY ) && pTFVictim->GetActiveTFWeapon() )
+ {
+ if ( event->GetInt( "weaponid" ) == TF_WEAPON_KNIFE )
+ {
+ if ( pTFVictim->GetActiveTFWeapon()->GetWeaponID() == TF_WEAPON_REVOLVER )
+ {
+ IncrementCount();
+ }
+ }
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyKillSpyWithKnife, ACHIEVEMENT_TF_SPY_KILL_SPY_WITH_KNIFE, "TF_SPY_KILL_SPY_WITH_KNIFE", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyRevengeBackstab : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ int customkill = event->GetInt( "customkill" );
+ if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
+ {
+ bool bRevenge = event->GetInt( "death_flags" ) & TF_DEATH_REVENGE;
+
+ if ( bRevenge == true )
+ {
+ IncrementCount();
+ }
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyRevengeBackstab, ACHIEVEMENT_TF_SPY_REVENGE_WITH_BACKSTAB, "TF_SPY_REVENGE_WITH_BACKSTAB", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyKnifeKillWhileJarated : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ if ( event->GetInt( "weaponid" ) == TF_WEAPON_KNIFE )
+ {
+ CTFPlayer *pTFAttacker = ToTFPlayer( pAttacker );
+ if ( pTFAttacker && pTFAttacker->m_Shared.InCond( TF_COND_URINE ) )
+ {
+ IncrementCount();
+ }
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyKnifeKillWhileJarated, ACHIEVEMENT_TF_SPY_KNIFE_KILL_WHILE_JARATED, "TF_SPY_KNIFE_KILL_WHILE_JARATED", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyBackstabGrind : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1000 );
+ SetStoreProgressInSteam( true );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ int customkill = event->GetInt( "customkill" );
+ if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
+ {
+ IncrementCount();
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabGrind, ACHIEVEMENT_TF_SPY_BACKSTAB_GRIND, "TF_SPY_BACKSTAB_GRIND", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyBackstabMedicCharged : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+ }
+
+ // server awards this achievement, no other code within achievement necessary
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabMedicCharged, ACHIEVEMENT_TF_SPY_BACKSTAB_MEDIC_CHARGED, "TF_SPY_BACKSTAB_MEDIC_CHARGED", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyBackstabDominatingEnemy : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ int customkill = event->GetInt( "customkill" );
+ if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
+ {
+ CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
+ if ( pTFVictim )
+ {
+ int nDominationsNeeded = ( event->GetInt( "revenge" ) > 0 ) ? 4 : 3;
+
+ if ( g_TF_PR && g_TF_PR->GetActiveDominations( pTFVictim->entindex() ) >= nDominationsNeeded )
+ {
+ IncrementCount();
+ }
+ }
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabDominatingEnemy, ACHIEVEMENT_TF_SPY_BACKSTAB_DOMINATING_ENEMY, "TF_SPY_BACKSTAB_DOMINATING_ENEMY", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyBackstabFriends : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 10 );
+ SetStoreProgressInSteam( true );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ int customkill = event->GetInt( "customkill" );
+ if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
+ {
+ if ( !steamapicontext->SteamFriends() || !steamapicontext->SteamUtils() || !g_pGameRules->IsMultiplayer() )
+ return;
+
+ player_info_t pi;
+ if ( !engine->GetPlayerInfo( pVictim->entindex(), &pi ) )
+ return;
+
+ if ( !pi.friendsID )
+ return;
+
+ // check and see if they're on the local player's friends list
+ CSteamID steamID( pi.friendsID, 1, GetUniverse(), k_EAccountTypeIndividual );
+ if ( steamapicontext->SteamFriends()->HasFriend( steamID, k_EFriendFlagImmediate ) )
+ {
+ IncrementCount();
+ }
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabFriends, ACHIEVEMENT_TF_SPY_BACKSTAB_FRIENDS, "TF_SPY_BACKSTAB_FRIENDS", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyAmbassadorGrind : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 50 );
+ SetStoreProgressInSteam( true );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ if ( event->GetInt( "weaponid" ) == TF_WEAPON_REVOLVER )
+ {
+ if ( FStrEq( event->GetString( "weapon_logclassname", "" ), "ambassador" ) )
+ {
+ IncrementCount();
+ }
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyAmbassadorGrind, ACHIEVEMENT_TF_SPY_AMBASSADOR_GRIND, "TF_SPY_AMBASSADOR_GRIND", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyAmbassadorSniperGrind : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 20 );
+ SetStoreProgressInSteam( true );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
+ if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SNIPER ) )
+ {
+ if ( event->GetInt( "weaponid" ) == TF_WEAPON_REVOLVER )
+ {
+ if ( FStrEq( event->GetString( "weapon_logclassname", "" ), "ambassador" ) )
+ {
+ if ( IsHeadshot( event->GetInt( "customkill" ) ) )
+ {
+ IncrementCount();
+ }
+ }
+ }
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyAmbassadorSniperGrind, ACHIEVEMENT_TF_SPY_AMBASSADOR_SNIPER_GRIND, "TF_SPY_AMBASSADOR_SNIPER_GRIND", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyAmbassadorScoutGrind : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 3 );
+ SetStoreProgressInSteam( true );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
+ if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SCOUT ) )
+ {
+ if ( event->GetInt( "weaponid" ) == TF_WEAPON_REVOLVER )
+ {
+ if ( FStrEq( event->GetString( "weapon_logclassname", "" ), "ambassador" ) )
+ {
+ if ( IsHeadshot( event->GetInt( "customkill" ) ) )
+ {
+ IncrementCount();
+ }
+ }
+ }
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyAmbassadorScoutGrind, ACHIEVEMENT_TF_SPY_AMBASSADOR_SCOUT_GRIND, "TF_SPY_AMBASSADOR_SCOUT_GRIND", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyMedicHealingKillEnemy : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ for ( int i = 1 ; i <= gpGlobals->maxClients ; i++ )
+ {
+ CTFPlayer *pTFPlayer = ToTFPlayer( UTIL_PlayerByIndex( i ) );
+
+ // can't kill the enemy medic that's healing you for this one...should be a different enemy
+ if ( pTFPlayer && ( pTFPlayer != pAttacker ) && ( pTFPlayer != pVictim ) )
+ {
+ // make sure they're not on our team
+ if ( pAttacker->GetTeamNumber() != pTFPlayer->GetTeamNumber() )
+ {
+ // are they a medic that's healing me?
+ if ( pTFPlayer->IsPlayerClass( TF_CLASS_MEDIC ) && pTFPlayer->MedicGetHealTarget() == pAttacker )
+ {
+ IncrementCount();
+ }
+ }
+ }
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyMedicHealingKillEnemy, ACHIEVEMENT_TF_SPY_MEDIC_HEALING_KILL_ENEMY, "TF_SPY_MEDIC_HEALING_KILL_ENEMY", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyBackstabQuickKills : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ int customkill = event->GetInt( "customkill" );
+ if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
+ {
+ int iNewIndex = m_Times.AddToTail();
+ m_Times[iNewIndex] = gpGlobals->curtime;
+
+ // we only care about the last three times we backstabbed someone
+ if ( m_Times.Count() > 3 )
+ {
+ m_Times.Remove( 0 );
+ }
+
+ if ( m_Times.Count() == 3 )
+ {
+ if ( m_Times.Tail() - m_Times.Head() <= 10.0 )
+ {
+ IncrementCount();
+ }
+ }
+ }
+ }
+ }
+
+private:
+ CUtlVector< float > m_Times;
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabQuickKills, ACHIEVEMENT_TF_SPY_BACKSTAB_QUICK_KILLS, "TF_SPY_BACKSTAB_QUICK_KILLS", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyTauntKill : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ // we already know we killed a player because of the ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS flag
+ // was this a taunt kill?
+ if ( event->GetInt( "customkill" ) == TF_DMG_CUSTOM_TAUNTATK_FENCING )
+ {
+ IncrementCount();
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyTauntKill, ACHIEVEMENT_TF_SPY_TAUNT_KILL, "TF_SPY_TAUNT_KILL", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyBackstabCappingEnemies : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 50 );
+ SetStoreProgressInSteam( true );
+ }
+
+ // server awards this achievement, no other code within achievement necessary
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabCappingEnemies, ACHIEVEMENT_TF_SPY_BACKSTAB_CAPPING_ENEMIES, "TF_SPY_BACKSTAB_CAPPING_ENEMIES", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyKillCPDefenders : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 15 );
+ SetStoreProgressInSteam( true );
+ }
+
+ // server awards this achievement, no other code within achievement necessary
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyKillCPDefenders, ACHIEVEMENT_TF_SPY_KILL_CP_DEFENDERS, "TF_SPY_KILL_CP_DEFENDERS", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+//FYI I'm a spy
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_FYIMedic : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_KILL_EVENTS );
+ SetGoal( 1 );
+ m_hTargets.Purge();
+ }
+
+ virtual void ListenForEvents( void )
+ {
+ ListenForGameEvent( "player_healedbymedic" );
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ if ( FStrEq( event->GetName(), "player_healedbymedic" ) )
+ {
+ int iEntity = event->GetInt( "medic" );
+
+ int iMedic = GetTargetIndex( UTIL_PlayerByIndex( iEntity ) );
+
+ if ( iMedic == -1 )
+ {
+ AddNewTarget( UTIL_PlayerByIndex( iEntity ) );
+ }
+ else
+ {
+ m_hTargets[iMedic].flRemoveTime = gpGlobals->curtime + 5.0f;
+ }
+ }
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_TFPlayer::GetLocalTFPlayer() )
+ {
+ int iMedic = GetTargetIndex( pVictim );
+
+ if ( iMedic != -1 )
+ {
+ if ( m_hTargets[iMedic].flRemoveTime >= gpGlobals->curtime )
+ {
+ IncrementCount();
+ }
+
+ m_hTargets.Remove( iMedic );
+ }
+ }
+ }
+
+ int GetTargetIndex( CBaseEntity *pTarget )
+ {
+ for ( int i = 0; i < m_hTargets.Count(); i++ )
+ {
+ if ( m_hTargets[i].hTarget == pTarget )
+ return i;
+ }
+ return -1;
+ }
+
+ void AddNewTarget( CBaseEntity *pTarget )
+ {
+ if ( !pTarget )
+ return;
+
+ // see if the target is already in our list or get a new index
+ int iMedic = GetTargetIndex( pTarget );
+ if ( iMedic == -1 )
+ {
+ iMedic = m_hTargets.AddToTail();
+ }
+
+ m_hTargets[iMedic].hTarget = pTarget;
+ m_hTargets[iMedic].flRemoveTime = gpGlobals->curtime + 5.0f;
+ }
+
+private:
+ struct targets_t
+ {
+ EHANDLE hTarget;
+ float flRemoveTime;
+ };
+
+ CUtlVector<targets_t> m_hTargets;
+};
+
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_FYIMedic, ACHIEVEMENT_TF_SPY_BACKSTAB_MEDIC_HEALING_YOU, "TF_SPY_BACKSTAB_MEDIC_HEALING_YOU", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+// Backstab a medic/heavy pair
+// NOTE: Enough of this, this should be a shared achievement class.
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_KillMedicPair : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+ }
+
+ virtual void ListenForEvents( void )
+ {
+ ListenForGameEvent( "localplayer_respawn" );
+ ListenForGameEvent( "teamplay_round_active" );
+
+ m_hTargets.Purge();
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ const char *pszEventName = event->GetName();
+
+ if ( FStrEq( pszEventName, "localplayer_respawn" ) ||
+ FStrEq( pszEventName, "teamplay_round_active" ) )
+ {
+ m_hTargets.Purge();
+ }
+ }
+
+ int GetTargetIndex( CBaseEntity *pTarget )
+ {
+ for ( int i = 0; i < m_hTargets.Count(); i++ )
+ {
+ if ( m_hTargets[i].hTarget == pTarget )
+ return i;
+ }
+ return -1;
+ }
+
+ void AddNewTarget( CBaseEntity *pTarget )
+ {
+ if ( !pTarget )
+ return;
+
+ // see if the target is already in our list or get a new index
+ int iTargetIndex = GetTargetIndex( pTarget );
+ if ( iTargetIndex == -1 )
+ {
+ iTargetIndex = m_hTargets.AddToTail();
+ }
+
+ m_hTargets[iTargetIndex].hTarget = pTarget;
+ m_hTargets[iTargetIndex].flTimeToBeat = gpGlobals->curtime + 10.0f; // 10 seconds to kill the target
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( !pVictim || !pVictim->IsPlayer() )
+ return;
+
+ C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
+
+ int customkill = event->GetInt( "customkill" );
+
+ if ( pLocalPlayer == pAttacker && customkill == TF_DMG_CUSTOM_BACKSTAB )
+ {
+ // is this victim in our list of targets?
+ int index = GetTargetIndex( pVictim );
+ if ( index != -1 )
+ {
+ // did we beat the time?
+ if ( m_hTargets[index].flTimeToBeat > gpGlobals->curtime )
+ {
+ IncrementCount();
+ }
+ }
+ else
+ {
+ C_TFPlayer *pNewTarget = NULL;
+ C_TFPlayer *pTFVictim = ToTFPlayer( pVictim );
+ if ( !pTFVictim->IsPlayerClass( TF_CLASS_MEDIC ) )
+ {
+ for ( int i = 1 ; i <= gpGlobals->maxClients ; i++ )
+ {
+ pNewTarget = ToTFPlayer( UTIL_PlayerByIndex( i ) );
+ if ( pNewTarget && pNewTarget->IsPlayerClass( TF_CLASS_MEDIC ) && pNewTarget->MedicGetHealTarget() == pTFVictim )
+ {
+ // add all of his Medics to our list of targets (could be more than one Medic)
+ AddNewTarget( pNewTarget );
+ }
+ }
+ }
+ else
+ {
+ pNewTarget = ToTFPlayer( pTFVictim->MedicGetHealTarget() );
+ if ( pNewTarget )
+ {
+ AddNewTarget( pNewTarget );
+ }
+ }
+ }
+ }
+ // is this victim in our list of targets?
+ int index_ = GetTargetIndex( pVictim );
+ if ( index_ != -1 )
+ {
+ m_hTargets.Remove( index_ );
+ }
+ }
+
+private:
+ struct targets_t
+ {
+ EHANDLE hTarget;
+ float flTimeToBeat;
+ };
+
+ CUtlVector<targets_t> m_hTargets;
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_KillMedicPair, ACHIEVEMENT_TF_SPY_BACKSTAB_MEDIC_PAIR, "TF_SPY_BACKSTAB_MEDIC_PAIR", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+//Destroy 3 enemy sentries
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SapBuildingGrind : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1000 );
+ SetStoreProgressInSteam( true );
+ }
+
+ virtual void ListenForEvents()
+ {
+ ListenForGameEvent( "object_destroyed" );
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ if ( Q_strcmp( event->GetName(), "object_destroyed" ) == 0 )
+ {
+ int iIndex = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
+
+ if ( iIndex == GetLocalPlayerIndex() )
+ {
+ const char *pWeapon = event->GetString( "weapon" );
+
+ if ( FStrEq( "obj_attachment_sapper", pWeapon ) )
+ {
+ IncrementCount();
+ }
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SapBuildingGrind, ACHIEVEMENT_TF_SPY_SAPPER_GRIND, "TF_SPY_SAPPER_GRIND", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+//Kill whoever triggered your feign death
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_FeignDeathKill : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+ m_iKillerIndex = 0;
+ m_flTriggerTime = gpGlobals->curtime;
+ }
+
+ virtual void ListenForEvents()
+ {
+ ListenForGameEvent( "player_death" );
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ if ( Q_strcmp( event->GetName(), "player_death" ) == 0 )
+ {
+ int iAttacker = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
+ int iVictim = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
+
+ if ( iVictim == GetLocalPlayerIndex() )
+ {
+ //Someone popped my feign death
+ if ( event->GetInt( "death_flags" ) & TF_DEATH_FEIGN_DEATH )
+ {
+ m_iKillerIndex = iAttacker;
+ m_flTriggerTime = gpGlobals->curtime + 20.0f;
+ }
+ }
+ }
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ C_TFPlayer *pTFVictim = ToTFPlayer( pVictim );
+
+ if ( pTFVictim && pTFVictim->entindex() == m_iKillerIndex && m_flTriggerTime >= gpGlobals->curtime )
+ {
+ IncrementCount();
+ }
+ }
+ }
+
+private:
+ int m_iKillerIndex;
+ float m_flTriggerTime;
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_FeignDeathKill, ACHIEVEMENT_TF_SPY_FEIGN_DEATH_KILL, "TF_SPY_FEIGN_DEATH_KILL", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+//Kill a sniper after breaking his shield
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_ShieldKill : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+
+ m_iBlockerIndex = 0;
+ m_flAttackTime = 0.0f;
+ }
+
+ virtual void ListenForEvents( void )
+ {
+ ListenForGameEvent( "player_shield_blocked" );
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ if ( FStrEq( event->GetName(), "player_shield_blocked" ) )
+ {
+ int iAttacker = event->GetInt( "attacker_entindex" );
+ int iBlocker = event->GetInt( "blocker_entindex" );
+
+ if ( GetLocalPlayerIndex() != iAttacker )
+ return;
+
+ m_iBlockerIndex = iBlocker;
+ m_flAttackTime = gpGlobals->curtime + 10.0f;
+ }
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( m_flAttackTime <= gpGlobals->curtime )
+ {
+ m_iBlockerIndex = 0;
+ return;
+ }
+
+ CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
+
+ if ( pTFVictim && pTFVictim->entindex() == m_iBlockerIndex && pAttacker == C_TFPlayer::GetLocalTFPlayer() )
+ {
+ IncrementCount();
+ }
+ }
+
+private:
+ int m_iBlockerIndex;
+ float m_flAttackTime;
+};
+
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_ShieldKill, ACHIEVEMENT_TF_SPY_BREAK_SHIELD_KILL_SNIPER, "TF_SPY_BREAK_SHIELD_KILL_SNIPER", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_KillWorkingEngineer : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+ SetStoreProgressInSteam( true );
+ }
+
+ // server awards this achievement, no other code within achievement necessary
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_KillWorkingEngineer, ACHIEVEMENT_TF_SPY_KILL_WORKING_ENGY, "TF_SPY_KILL_WORKING_ENGY", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_TFSpySurviveBurning : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+ m_bIsThinking = false;
+ }
+
+ virtual void ListenForEvents()
+ {
+ ListenForGameEvent( "player_damaged" );
+ ListenForGameEvent( "teamplay_round_start" );
+ ListenForGameEvent( "localplayer_respawn" );
+ m_bIsThinking = false;
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
+ if ( !pLocalPlayer )
+ return;
+
+ const char *pszEventName = event->GetName();
+
+ if ( FStrEq( pszEventName, "localplayer_respawn" ) || FStrEq( pszEventName, "teamplay_round_active" ) )
+ {
+ ClearThink();
+ m_bIsThinking = false;
+ return;
+ }
+
+ // Have I taken damage?
+ if ( FStrEq( pszEventName, "player_damaged" ))
+ {
+ int iDmgType = event->GetInt( "type" );
+
+ // Did I survive the damage event?
+ if ( pLocalPlayer->IsAlive() && !m_bIsThinking )
+ {
+ // Am I on fire?
+ if ( (iDmgType & DMG_IGNITE) )
+ {
+ // Am I cloaked?
+ if ( pLocalPlayer->m_Shared.InCond ( TF_COND_STEALTHED ) )
+ {
+ SetNextThink( 30 );
+ m_bIsThinking = true;
+ }
+ }
+ }
+ }
+ }
+
+ virtual void Think( void )
+ {
+ C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
+ if ( pLocalPlayer && pLocalPlayer->IsAlive())
+ {
+ IncrementCount();
+ }
+ }
+
+private:
+ bool m_bIsThinking;
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_TFSpySurviveBurning, ACHIEVEMENT_TF_SPY_SURVIVE_BURNING, "TF_SPY_SURVIVE_BURNING", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyBackstabEnemySwitchPyro : public CBaseTFAchievementSimple
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+
+ ResetBackstabbedPlayers();
+ }
+
+ virtual void ListenForEvents()
+ {
+ ListenForGameEvent( "player_spawn" );
+ ListenForGameEvent( "localplayer_changeclass" );
+ ListenForGameEvent( "localplayer_changeteam" );
+ }
+
+ void ResetBackstabbedPlayers( void )
+ {
+ m_BackstabbedPlayers.Purge();
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ // no progress in endround
+ if ( !GameRulesAllowsAchievements() )
+ return;
+
+ if ( !IsLocalTFPlayerClass( TF_CLASS_SPY ) )
+ return;
+
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ int customkill = event->GetInt( "customkill" );
+ if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
+ {
+ CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
+ if ( pTFVictim && !pTFVictim->IsPlayerClass( TF_CLASS_PYRO ) ) // they can't already be a pyro for this one
+ {
+ int nUserID = pTFVictim->GetUserID();
+
+ if ( m_BackstabbedPlayers.Find( nUserID ) == m_BackstabbedPlayers.InvalidIndex() )
+ {
+ // they're not in our list yet, add them
+ m_BackstabbedPlayers.AddToTail( nUserID );
+ }
+ }
+ }
+ }
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ const char *pszEventName = event->GetName();
+
+ if ( FStrEq( pszEventName, "player_spawn" ) )
+ {
+ // no progress in endround
+ if ( !GameRulesAllowsAchievements() )
+ return;
+
+ if ( !IsLocalTFPlayerClass( TF_CLASS_SPY ) )
+ return;
+
+ const int nUserID = event->GetInt( "userid" );
+ int iIndex = m_BackstabbedPlayers.Find( nUserID );
+ if ( iIndex != m_BackstabbedPlayers.InvalidIndex() )
+ {
+ const int nTeam = event->GetInt( "team" );
+ if ( nTeam != GetLocalPlayerTeam() )
+ {
+ const int nClass = event->GetInt( "class" );
+ if ( nClass == TF_CLASS_PYRO )
+ {
+ IncrementCount();
+ }
+ }
+
+ m_BackstabbedPlayers.Remove( iIndex );
+ }
+ }
+ else if ( FStrEq( pszEventName, "localplayer_changeclass" ) ||
+ FStrEq( pszEventName, "localplayer_changeteam" ) )
+ {
+ ResetBackstabbedPlayers();
+ }
+ }
+
+private:
+ CUtlVector< int > m_BackstabbedPlayers;
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabEnemySwitchPyro, ACHIEVEMENT_TF_SPY_BACKSTAB_ENEMY_SWITCH_PYRO, "TF_SPY_BACKSTAB_ENEMY_SWITCH_PYRO", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyBackstabEngySapBuilding : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+
+ m_hTargets.Purge();
+ }
+
+ virtual void ListenForEvents()
+ {
+ ListenForGameEvent( "player_sapped_object" );
+ }
+
+ int FindEngyInList( CBaseEntity *pTarget )
+ {
+ for ( int i = 0; i < m_hTargets.Count(); i++ )
+ {
+ if ( m_hTargets[i].hEngy == pTarget )
+ return i;
+ }
+ return -1;
+ }
+
+ int CountSappedObjects( int iIndex )
+ {
+ int nCount = 0;
+
+ if ( m_hTargets.IsValidIndex( iIndex ) )
+ {
+ if ( m_hTargets[iIndex].bSentry )
+ {
+ nCount++;
+ }
+
+ if ( m_hTargets[iIndex].bDispenser )
+ {
+ nCount++;
+ }
+
+ if ( m_hTargets[iIndex].bTele )
+ {
+ nCount++;
+ }
+ }
+
+ return nCount;
+ }
+
+ void SetObjectSapped( int iIndex, int nType )
+ {
+ if ( m_hTargets.IsValidIndex( iIndex ) )
+ {
+ switch( nType )
+ {
+ case OBJ_SENTRYGUN:
+ m_hTargets[iIndex].bSentry = true;
+ break;
+ case OBJ_DISPENSER:
+ m_hTargets[iIndex].bDispenser = true;
+ break;
+ case OBJ_TELEPORTER:
+ m_hTargets[iIndex].bTele = true;
+ break;
+ }
+ }
+ }
+
+ void CheckAchievementEarned( void )
+ {
+ for ( int i = m_hTargets.Count() - 1; i >= 0; i-- )
+ {
+ if ( m_hTargets[i].flTimeToBeat < gpGlobals->curtime )
+ {
+ // time has run out on this one
+ m_hTargets.Remove( i );
+ }
+ else
+ {
+ if ( CountSappedObjects( i ) >= 3 )
+ {
+ IncrementCount();
+ m_hTargets.Purge();
+ return;
+ }
+ }
+ }
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ int customkill = event->GetInt( "customkill" );
+ if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
+ {
+ CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
+ if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_ENGINEER ) )
+ {
+ int iIndex = FindEngyInList( pVictim );
+ if ( iIndex == -1 )
+ {
+ iIndex = m_hTargets.AddToTail();
+ }
+
+ m_hTargets[iIndex].hEngy = pVictim;
+ m_hTargets[iIndex].bSentry = false;
+ m_hTargets[iIndex].bDispenser = false;
+ m_hTargets[iIndex].bTele = false;
+ m_hTargets[iIndex].flTimeToBeat = gpGlobals->curtime + 10.0;
+ }
+ }
+
+ CheckAchievementEarned(); // checks the achievement list, but also cleans out old entries (based on flTimeToBeat)
+ }
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ const char *pszEventName = event->GetName();
+
+ if ( FStrEq( pszEventName, "player_sapped_object" ) )
+ {
+ int nUserID = event->GetInt( "userid" );
+
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( engine->GetPlayerForUserID( nUserID ) );
+ if ( pPlayer == C_BasePlayer::GetLocalPlayer() )
+ {
+ CBasePlayer *pEngy = UTIL_PlayerByIndex( engine->GetPlayerForUserID( event->GetInt( "ownerid" ) ) );
+
+ int iIndex = FindEngyInList( pEngy );
+ if ( iIndex != -1 )
+ {
+ SetObjectSapped( iIndex, event->GetInt( "object" ) );
+ }
+
+ CheckAchievementEarned(); // checks the achievement list, but also cleans out old entries (based on flTimeToBeat)
+ }
+ }
+ }
+
+private:
+ struct targets_t
+ {
+ EHANDLE hEngy;
+ bool bSentry;
+ bool bDispenser;
+ bool bTele;
+ float flTimeToBeat;
+ };
+
+ CUtlVector<targets_t> m_hTargets;
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabEngySapBuilding, ACHIEVEMENT_TF_SPY_BACKSTAB_ENGY_SAP_BUILDING, "TF_SPY_BACKSTAB_ENGY_SAP_BUILDING", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpySapBuildingBackstabEngy : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+
+ m_hTargets.Purge();
+ }
+
+ virtual void ListenForEvents()
+ {
+ ListenForGameEvent( "player_sapped_object" );
+ }
+
+ int FindEngyInList( CBaseEntity *pTarget )
+ {
+ for ( int i = 0; i < m_hTargets.Count(); i++ )
+ {
+ if ( m_hTargets[i].hEngy == pTarget )
+ return i;
+ }
+ return -1;
+ }
+
+ void ValidateList( void )
+ {
+ for ( int i = m_hTargets.Count() - 1; i >= 0; i-- )
+ {
+ if ( m_hTargets[i].flTimeToBeat < gpGlobals->curtime )
+ {
+ // time has run out on this one
+ m_hTargets.Remove( i );
+ }
+ }
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ int customkill = event->GetInt( "customkill" );
+ if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
+ {
+ CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
+ if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_ENGINEER ) )
+ {
+ int iIndex = FindEngyInList( pVictim );
+ if ( iIndex != -1 )
+ {
+ // they're in our list...is the time still valid?
+ if ( m_hTargets[iIndex].flTimeToBeat > gpGlobals->curtime )
+ {
+ IncrementCount();
+ m_hTargets.Purge();
+ return;
+ }
+ }
+ }
+ }
+
+ ValidateList();
+ }
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ const char *pszEventName = event->GetName();
+
+ if ( FStrEq( pszEventName, "player_sapped_object" ) )
+ {
+ int nUserID = event->GetInt( "userid" );
+
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( engine->GetPlayerForUserID( nUserID ) );
+ if ( pPlayer == C_BasePlayer::GetLocalPlayer() )
+ {
+ CBasePlayer *pEngy = UTIL_PlayerByIndex( engine->GetPlayerForUserID( event->GetInt( "ownerid" ) ) );
+ if ( pEngy )
+ {
+ int iIndex = FindEngyInList( pEngy );
+ if ( iIndex == -1 )
+ {
+ iIndex = m_hTargets.AddToTail();
+ }
+
+ m_hTargets[iIndex].hEngy = pEngy;
+ m_hTargets[iIndex].flTimeToBeat = gpGlobals->curtime + 5.0;
+ }
+
+ ValidateList();
+ }
+ }
+ }
+
+private:
+ struct targets_t
+ {
+ EHANDLE hEngy;
+ float flTimeToBeat;
+ };
+
+ CUtlVector<targets_t> m_hTargets;
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpySapBuildingBackstabEngy, ACHIEVEMENT_TF_SPY_SAP_BUILDING_BACKSTAB_ENGY, "TF_SPY_SAP_BUILDING_BACKSTAB_ENGY", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SapperTeamwork : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+
+ ResetData();
+ }
+
+ virtual void ListenForEvents()
+ {
+ ListenForGameEvent( "player_sapped_object" );
+ ListenForGameEvent( "localplayer_changeteam" );
+ }
+
+ void ResetData( void )
+ {
+ m_hTeammates.Purge();
+
+ m_nLocalPlayerTarget = -1;
+ m_flLocalPlayerTime = -1;
+ }
+
+ int FindSpyInList( int userid )
+ {
+ for ( int i = 0; i < m_hTeammates.Count(); i++ )
+ {
+ if ( m_hTeammates[i].nSpy == userid )
+ return i;
+ }
+ return -1;
+ }
+
+ void CheckAchievementEarned( void )
+ {
+ // has the local player sapped anything?
+ if ( m_nLocalPlayerTarget == -1 && m_flLocalPlayerTime == -1 )
+ return;
+
+ // has it been longer than 3 seconds since the local player sapped something?
+ if ( gpGlobals->curtime - m_flLocalPlayerTime > 3.0 )
+ {
+ // reset the local player target and time, this fixes the local player sapping something and
+ // then a teammate saps something > 3 seconds later (otherwise, the new entry would be removed in the for loop below)
+ m_nLocalPlayerTarget = -1;
+ m_flLocalPlayerTime = -1;
+ return;
+ }
+
+ for ( int i = m_hTeammates.Count() - 1; i >= 0; i-- )
+ {
+ if ( m_hTeammates[i].nTarget != m_nLocalPlayerTarget ) // different guns
+ {
+ if ( fabs( m_hTeammates[i].flTime - m_flLocalPlayerTime ) <= 3.0 )
+ {
+ IncrementCount();
+ ResetData();
+ return;
+ }
+ else
+ {
+ m_hTeammates.Remove( i );
+ }
+ }
+ }
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ const char *pszEventName = event->GetName();
+
+ if ( FStrEq( pszEventName, "player_sapped_object" ) )
+ {
+ if ( event->GetInt( "object" ) == OBJ_SENTRYGUN )
+ {
+ int nUserID = event->GetInt( "userid" );
+
+ CTFPlayer *pSpy = ToTFPlayer( UTIL_PlayerByIndex( engine->GetPlayerForUserID( nUserID ) ) );
+ if ( pSpy && pSpy->GetTeamNumber() == GetLocalPlayerTeam() )
+ {
+ if ( pSpy == C_BasePlayer::GetLocalPlayer() )
+ {
+ m_nLocalPlayerTarget = event->GetInt( "ownerid" );
+ m_flLocalPlayerTime = gpGlobals->curtime;
+ }
+ else
+ {
+ int iIndex = FindSpyInList( nUserID );
+ if ( iIndex == -1 )
+ {
+ iIndex = m_hTeammates.AddToTail();
+ }
+
+ m_hTeammates[iIndex].nSpy = nUserID;
+ m_hTeammates[iIndex].nTarget = event->GetInt( "ownerid" );
+ m_hTeammates[iIndex].flTime = gpGlobals->curtime;
+ }
+
+ CheckAchievementEarned(); // checks the achievement list, but also cleans out old entries (based on time)
+ }
+ }
+ }
+ else if ( FStrEq( pszEventName, "localplayer_changeteam" ) )
+ {
+ ResetData();
+ }
+ }
+
+private:
+ struct teammates_t
+ {
+ int nSpy; // who built the sapper
+ int nTarget; // owner of the gun
+ float flTime; // time it was sapped
+ };
+
+ CUtlVector<teammates_t> m_hTeammates; // list of teammates who have sapped guns
+
+ int m_nLocalPlayerTarget; // owner of the gun
+ float m_flLocalPlayerTime; // time it was sapped
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SapperTeamwork, ACHIEVEMENT_TF_SPY_SAPPER_TEAMWORK, "TF_SPY_SAPPER_TEAMWORK", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_SpyCampPosition : public CBaseTFAchievement
+{
+ void Init()
+ {
+ SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
+ SetGoal( 1 );
+
+ ResetData();
+ }
+
+ void ResetData()
+ {
+ m_hTargets.Purge();
+ }
+
+ virtual void ListenForEvents( void )
+ {
+ ListenForGameEvent( "localplayer_respawn" );
+ ListenForGameEvent( "teamplay_round_active" );
+
+ ResetData();
+ }
+
+ int FindEnemyInList( CBaseEntity *pTarget )
+ {
+ for ( int i = 0; i < m_hTargets.Count(); i++ )
+ {
+ if ( m_hTargets[i].hEnemy == pTarget )
+ return i;
+ }
+ return -1;
+ }
+
+ void FireGameEvent_Internal( IGameEvent *event )
+ {
+ const char *pszEventName = event->GetName();
+
+ if ( FStrEq( pszEventName, "localplayer_respawn" ) ||
+ FStrEq( pszEventName, "teamplay_round_active" ) )
+ {
+ ResetData();
+ }
+ }
+
+ bool LocalPlayerHasMotionCloakEquipped( void )
+ {
+ CTFPlayer *pPlayer = ToTFPlayer( C_BasePlayer::GetLocalPlayer() );
+ if ( pPlayer )
+ {
+ CTFWeaponInvis *pWeapon = (CTFWeaponInvis *) pPlayer->Weapon_OwnsThisID( TF_WEAPON_INVIS );
+ if ( pWeapon && pWeapon->HasMotionCloak() )
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
+ {
+ if ( LocalPlayerHasMotionCloakEquipped() )
+ {
+ int iIndex = FindEnemyInList( pVictim );
+ if ( iIndex != -1 )
+ {
+ // they're already in our list
+ Vector vecOrigin = pVictim->GetAbsOrigin();
+
+ if ( ( m_hTargets[iIndex].vecOrigin - vecOrigin ).LengthSqr() > (1024*1024) )
+ {
+ // we killed them too far away from our last position, so reset
+ m_hTargets[iIndex].nKillCount = 1;
+ m_hTargets[iIndex].vecOrigin = vecOrigin;
+ }
+ else
+ {
+ // they were close enough, so add to our kill count
+ m_hTargets[iIndex].nKillCount++;
+ }
+ }
+ else
+ {
+ // they're new to our list
+ iIndex = m_hTargets.AddToTail();
+
+ m_hTargets[iIndex].hEnemy = pVictim;
+ m_hTargets[iIndex].nKillCount = 1;
+ m_hTargets[iIndex].vecOrigin = pVictim->GetAbsOrigin();
+ }
+
+ if ( m_hTargets[iIndex].nKillCount >= 3 )
+ {
+ IncrementCount();
+ ResetData();
+ }
+ }
+ else
+ {
+ // Not using motion cloak anymore
+ ResetData();
+ }
+ }
+ }
+
+private:
+ struct targets_t
+ {
+ EHANDLE hEnemy;
+ int nKillCount;
+ Vector vecOrigin;
+ };
+
+ CUtlVector<targets_t> m_hTargets;
+
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyCampPosition, ACHIEVEMENT_TF_SPY_CAMP_POSITION, "TF_SPY_CAMP_POSITION", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_AchieveProgress1 : public CAchievement_AchievedCount
+{
+public:
+ DECLARE_CLASS( CAchievementTFSpy_AchieveProgress1, CAchievement_AchievedCount );
+ void Init()
+ {
+ BaseClass::Init();
+ SetAchievementsRequired( 5, ACHIEVEMENT_TF_SPY_START_RANGE, ACHIEVEMENT_TF_SPY_END_RANGE );
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_AchieveProgress1, ACHIEVEMENT_TF_SPY_ACHIEVE_PROGRESS1, "TF_SPY_ACHIEVE_PROGRESS1", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_AchieveProgress2 : public CAchievement_AchievedCount
+{
+public:
+ DECLARE_CLASS( CAchievementTFSpy_AchieveProgress2, CAchievement_AchievedCount );
+ void Init()
+ {
+ BaseClass::Init();
+ SetAchievementsRequired( 11, ACHIEVEMENT_TF_SPY_START_RANGE, ACHIEVEMENT_TF_SPY_END_RANGE );
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_AchieveProgress2, ACHIEVEMENT_TF_SPY_ACHIEVE_PROGRESS2, "TF_SPY_ACHIEVE_PROGRESS2", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_AchieveProgress3 : public CAchievement_AchievedCount
+{
+public:
+ DECLARE_CLASS( CAchievementTFSpy_AchieveProgress3, CAchievement_AchievedCount );
+ void Init()
+ {
+ BaseClass::Init();
+ SetAchievementsRequired( 17, ACHIEVEMENT_TF_SPY_START_RANGE, ACHIEVEMENT_TF_SPY_END_RANGE );
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_AchieveProgress3, ACHIEVEMENT_TF_SPY_ACHIEVE_PROGRESS3, "TF_SPY_ACHIEVE_PROGRESS3", 5 );
+
+//----------------------------------------------------------------------------------------------------------------
+class CAchievementTFSpy_KillBackScatterScout : public CBaseTFAchievement
+{
+public:
+ void Init()
+ {
+ SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
+ SetGoal( 1 );
+ }
+
+ virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
+ {
+ CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
+ if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SCOUT ) && ( pAttacker == C_TFPlayer::GetLocalTFPlayer() ) )
+ {
+ if ( event->GetInt( "customkill" ) == TF_DMG_CUSTOM_BACKSTAB )
+ {
+ CTFWeaponBase *pWeapon = pTFVictim->GetActiveTFWeapon();
+ if ( pWeapon && ( pWeapon->GetWeaponID() == TF_WEAPON_SCATTERGUN ) )
+ {
+ int iMiniCritBackAttack = 0;
+ CALL_ATTRIB_HOOK_INT_ON_OTHER( pWeapon, iMiniCritBackAttack, closerange_backattack_minicrits );
+ if ( iMiniCritBackAttack > 0 )
+ {
+ IncrementCount();
+ }
+ }
+ }
+ }
+ }
+};
+DECLARE_ACHIEVEMENT( CAchievementTFSpy_KillBackScatterScout, ACHIEVEMENT_TF_SPY_KILL_BACKSCATTER_SCOUT, "TF_SPY_KILL_BACKSCATTER_SCOUT", 5 );
+
+#endif // CLIENT_DLL