Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1773 lines
49 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #ifdef CLIENT_DLL
  8. #include "achievementmgr.h"
  9. #include "baseachievement.h"
  10. #include "tf_hud_statpanel.h"
  11. #include "c_tf_team.h"
  12. #include "c_tf_player.h"
  13. #include "c_tf_playerresource.h"
  14. #include "tf_gamerules.h"
  15. #include "achievements_tf.h"
  16. #include "c_tf_playerresource.h"
  17. #include "tf_weapon_invis.h"
  18. //======================================================================================================================================
  19. // SPY ACHIEVEMENT PACK
  20. //======================================================================================================================================
  21. //----------------------------------------------------------------------------------------------------------------
  22. class CAchievementTFSpy_SpyBackstabSnipers : public CBaseTFAchievement
  23. {
  24. void Init()
  25. {
  26. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  27. SetGoal( 1 );
  28. }
  29. void ResetTracking()
  30. {
  31. m_iSnipersKilled = 0;
  32. }
  33. virtual void ListenForEvents( void )
  34. {
  35. ListenForGameEvent( "localplayer_respawn" );
  36. ListenForGameEvent( "teamplay_round_active" );
  37. ResetTracking();
  38. }
  39. void FireGameEvent_Internal( IGameEvent *event )
  40. {
  41. const char *pszEventName = event->GetName();
  42. if ( FStrEq( pszEventName, "localplayer_respawn" ) ||
  43. FStrEq( pszEventName, "teamplay_round_active" ) )
  44. {
  45. ResetTracking();
  46. }
  47. }
  48. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  49. {
  50. // Achievement for backstabbing 3 snipers in a single life.
  51. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  52. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SNIPER ) )
  53. {
  54. int customkill = event->GetInt( "customkill" );
  55. if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
  56. {
  57. m_iSnipersKilled++;
  58. if ( m_iSnipersKilled == 3 )
  59. {
  60. IncrementCount();
  61. }
  62. }
  63. }
  64. }
  65. int m_iSnipersKilled;
  66. };
  67. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabSnipers, ACHIEVEMENT_TF_SPY_BACKSTAB_SNIPERS, "TF_SPY_BACKSTAB_SNIPERS", 5 );
  68. //----------------------------------------------------------------------------------------------------------------
  69. class CAchievementTFSpy_FreezecamFlick : public CBaseTFAchievement
  70. {
  71. // Achievement for freeze camming on a cig flick w/ enemy corpse on screen.
  72. void Init()
  73. {
  74. SetFlags( ACH_SAVE_GLOBAL );
  75. SetGoal( 1 );
  76. }
  77. };
  78. DECLARE_ACHIEVEMENT( CAchievementTFSpy_FreezecamFlick, ACHIEVEMENT_TF_SPY_FREEZECAM_FLICK, "TF_SPY_FREEZECAM_FLICK", 5 );
  79. //----------------------------------------------------------------------------------------------------------------
  80. class CAchievementTFSpy_SpyBackstabDisguisedSpy : public CBaseTFAchievement
  81. {
  82. void Init()
  83. {
  84. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  85. SetGoal( 1 );
  86. }
  87. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  88. {
  89. // Achievement for backstabbing a disguised spy.
  90. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  91. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SPY ) )
  92. {
  93. int customkill = event->GetInt( "customkill" );
  94. if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
  95. {
  96. if ( pTFVictim->m_Shared.InCond( TF_COND_DISGUISED ) )
  97. {
  98. IncrementCount();
  99. }
  100. }
  101. }
  102. }
  103. };
  104. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabDisguisedSpy, ACHIEVEMENT_TF_SPY_BACKSTAB_DISGUISED_SPY, "TF_SPY_BACKSTAB_DISGUISED_SPY", 5 );
  105. //----------------------------------------------------------------------------------------------------------------
  106. class CAchievementTFSpy_SpyBackstabDisguiseTarget : public CBaseTFAchievement
  107. {
  108. void Init()
  109. {
  110. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  111. SetGoal( 1 );
  112. }
  113. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  114. {
  115. // Achievement for backstabbing the player you are disguised as.
  116. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  117. CTFPlayer *pTFAttacker = ToTFPlayer( pAttacker );
  118. if ( pTFAttacker && pTFVictim && pTFVictim == pTFAttacker->m_Shared.GetDisguiseTarget().Get() )
  119. {
  120. int customkill = event->GetInt( "customkill" );
  121. if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
  122. {
  123. IncrementCount();
  124. }
  125. }
  126. }
  127. };
  128. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabDisguiseTarget, ACHIEVEMENT_TF_SPY_BACKSTAB_DISGUISE_TARGET, "TF_SPY_BACKSTAB_DISGUISE_TARGET", 5 );
  129. //----------------------------------------------------------------------------------------------------------------
  130. class CAchievementTFSpy_SpyFastCap : public CBaseTFAchievement
  131. {
  132. void Init()
  133. {
  134. SetFlags( ACH_SAVE_GLOBAL );
  135. SetGoal( 1 );
  136. }
  137. virtual void ListenForEvents( void )
  138. {
  139. ListenForGameEvent( "teamplay_point_startcapture" );
  140. }
  141. void FireGameEvent_Internal( IGameEvent *event )
  142. {
  143. // only on maps with capture points
  144. if ( TFGameRules() && TFGameRules()->GetGameType() != TF_GAMETYPE_CP && TFGameRules()->GetGameType() != TF_GAMETYPE_ARENA )
  145. return;
  146. const char *pszEventName = event->GetName();
  147. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  148. if ( !pLocalPlayer )
  149. return;
  150. if ( FStrEq( pszEventName, "teamplay_point_startcapture" ) )
  151. {
  152. const char *cappers = event->GetString( "cappers" );
  153. for ( int i=0; i<Q_strlen( cappers ); i++ )
  154. {
  155. int iPlayerIndex = (int) cappers[i];
  156. CTFPlayer *pPlayer = ToTFPlayer( UTIL_PlayerByIndex( iPlayerIndex ) );
  157. if ( pPlayer == pLocalPlayer )
  158. {
  159. if ( event->GetFloat( "captime" ) < 1.0 )
  160. {
  161. IncrementCount();
  162. }
  163. }
  164. }
  165. }
  166. }
  167. };
  168. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyFastCap, ACHIEVEMENT_TF_SPY_FAST_CAP, "TF_SPY_FAST_CAP", 5 );
  169. //----------------------------------------------------------------------------------------------------------------
  170. class CAchievementTFSpy_SpyDominateSniper : public CBaseTFAchievement
  171. {
  172. void Init()
  173. {
  174. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  175. SetGoal( 1 );
  176. }
  177. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  178. {
  179. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  180. {
  181. bool bDomination = event->GetInt( "death_flags" ) & TF_DEATH_DOMINATION;
  182. if ( bDomination == true )
  183. {
  184. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  185. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SNIPER ) )
  186. {
  187. IncrementCount();
  188. }
  189. }
  190. }
  191. }
  192. };
  193. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyDominateSniper, ACHIEVEMENT_TF_SPY_DOMINATE_SNIPER, "TF_SPY_DOMINATE_SNIPER", 5 );
  194. //----------------------------------------------------------------------------------------------------------------
  195. class CAchievementTFSpy_SpyBumpCloakedSpy : public CBaseTFAchievement
  196. {
  197. void Init()
  198. {
  199. SetFlags( ACH_SAVE_GLOBAL );
  200. SetGoal( 1 );
  201. }
  202. // server awards this achievement, no other code within achievement necessary
  203. };
  204. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBumpCloakedSpy, ACHIEVEMENT_TF_SPY_BUMP_CLOAKED_SPY, "TF_SPY_BUMP_CLOAKED_SPY", 5 );
  205. //----------------------------------------------------------------------------------------------------------------
  206. class CAchievementTFSpy_SpyKillSpyWithKnife : public CBaseTFAchievement
  207. {
  208. void Init()
  209. {
  210. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  211. SetGoal( 1 );
  212. }
  213. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  214. {
  215. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  216. {
  217. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  218. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SPY ) && pTFVictim->GetActiveTFWeapon() )
  219. {
  220. if ( event->GetInt( "weaponid" ) == TF_WEAPON_KNIFE )
  221. {
  222. if ( pTFVictim->GetActiveTFWeapon()->GetWeaponID() == TF_WEAPON_REVOLVER )
  223. {
  224. IncrementCount();
  225. }
  226. }
  227. }
  228. }
  229. }
  230. };
  231. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyKillSpyWithKnife, ACHIEVEMENT_TF_SPY_KILL_SPY_WITH_KNIFE, "TF_SPY_KILL_SPY_WITH_KNIFE", 5 );
  232. //----------------------------------------------------------------------------------------------------------------
  233. class CAchievementTFSpy_SpyRevengeBackstab : public CBaseTFAchievement
  234. {
  235. void Init()
  236. {
  237. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  238. SetGoal( 1 );
  239. }
  240. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  241. {
  242. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  243. {
  244. int customkill = event->GetInt( "customkill" );
  245. if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
  246. {
  247. bool bRevenge = event->GetInt( "death_flags" ) & TF_DEATH_REVENGE;
  248. if ( bRevenge == true )
  249. {
  250. IncrementCount();
  251. }
  252. }
  253. }
  254. }
  255. };
  256. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyRevengeBackstab, ACHIEVEMENT_TF_SPY_REVENGE_WITH_BACKSTAB, "TF_SPY_REVENGE_WITH_BACKSTAB", 5 );
  257. //----------------------------------------------------------------------------------------------------------------
  258. class CAchievementTFSpy_SpyKnifeKillWhileJarated : public CBaseTFAchievement
  259. {
  260. void Init()
  261. {
  262. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  263. SetGoal( 1 );
  264. }
  265. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  266. {
  267. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  268. {
  269. if ( event->GetInt( "weaponid" ) == TF_WEAPON_KNIFE )
  270. {
  271. CTFPlayer *pTFAttacker = ToTFPlayer( pAttacker );
  272. if ( pTFAttacker && pTFAttacker->m_Shared.InCond( TF_COND_URINE ) )
  273. {
  274. IncrementCount();
  275. }
  276. }
  277. }
  278. }
  279. };
  280. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyKnifeKillWhileJarated, ACHIEVEMENT_TF_SPY_KNIFE_KILL_WHILE_JARATED, "TF_SPY_KNIFE_KILL_WHILE_JARATED", 5 );
  281. //----------------------------------------------------------------------------------------------------------------
  282. class CAchievementTFSpy_SpyBackstabGrind : public CBaseTFAchievement
  283. {
  284. void Init()
  285. {
  286. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  287. SetGoal( 1000 );
  288. SetStoreProgressInSteam( true );
  289. }
  290. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  291. {
  292. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  293. {
  294. int customkill = event->GetInt( "customkill" );
  295. if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
  296. {
  297. IncrementCount();
  298. }
  299. }
  300. }
  301. };
  302. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabGrind, ACHIEVEMENT_TF_SPY_BACKSTAB_GRIND, "TF_SPY_BACKSTAB_GRIND", 5 );
  303. //----------------------------------------------------------------------------------------------------------------
  304. class CAchievementTFSpy_SpyBackstabMedicCharged : public CBaseTFAchievement
  305. {
  306. void Init()
  307. {
  308. SetFlags( ACH_SAVE_GLOBAL );
  309. SetGoal( 1 );
  310. }
  311. // server awards this achievement, no other code within achievement necessary
  312. };
  313. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabMedicCharged, ACHIEVEMENT_TF_SPY_BACKSTAB_MEDIC_CHARGED, "TF_SPY_BACKSTAB_MEDIC_CHARGED", 5 );
  314. //----------------------------------------------------------------------------------------------------------------
  315. class CAchievementTFSpy_SpyBackstabDominatingEnemy : public CBaseTFAchievement
  316. {
  317. void Init()
  318. {
  319. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  320. SetGoal( 1 );
  321. }
  322. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  323. {
  324. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  325. {
  326. int customkill = event->GetInt( "customkill" );
  327. if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
  328. {
  329. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  330. if ( pTFVictim )
  331. {
  332. int nDominationsNeeded = ( event->GetInt( "revenge" ) > 0 ) ? 4 : 3;
  333. if ( g_TF_PR && g_TF_PR->GetActiveDominations( pTFVictim->entindex() ) >= nDominationsNeeded )
  334. {
  335. IncrementCount();
  336. }
  337. }
  338. }
  339. }
  340. }
  341. };
  342. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabDominatingEnemy, ACHIEVEMENT_TF_SPY_BACKSTAB_DOMINATING_ENEMY, "TF_SPY_BACKSTAB_DOMINATING_ENEMY", 5 );
  343. //----------------------------------------------------------------------------------------------------------------
  344. class CAchievementTFSpy_SpyBackstabFriends : public CBaseTFAchievement
  345. {
  346. void Init()
  347. {
  348. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  349. SetGoal( 10 );
  350. SetStoreProgressInSteam( true );
  351. }
  352. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  353. {
  354. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  355. {
  356. int customkill = event->GetInt( "customkill" );
  357. if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
  358. {
  359. if ( !steamapicontext->SteamFriends() || !steamapicontext->SteamUtils() || !g_pGameRules->IsMultiplayer() )
  360. return;
  361. player_info_t pi;
  362. if ( !engine->GetPlayerInfo( pVictim->entindex(), &pi ) )
  363. return;
  364. if ( !pi.friendsID )
  365. return;
  366. // check and see if they're on the local player's friends list
  367. CSteamID steamID( pi.friendsID, 1, GetUniverse(), k_EAccountTypeIndividual );
  368. if ( steamapicontext->SteamFriends()->HasFriend( steamID, k_EFriendFlagImmediate ) )
  369. {
  370. IncrementCount();
  371. }
  372. }
  373. }
  374. }
  375. };
  376. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabFriends, ACHIEVEMENT_TF_SPY_BACKSTAB_FRIENDS, "TF_SPY_BACKSTAB_FRIENDS", 5 );
  377. //----------------------------------------------------------------------------------------------------------------
  378. class CAchievementTFSpy_SpyAmbassadorGrind : public CBaseTFAchievement
  379. {
  380. void Init()
  381. {
  382. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  383. SetGoal( 50 );
  384. SetStoreProgressInSteam( true );
  385. }
  386. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  387. {
  388. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  389. {
  390. if ( event->GetInt( "weaponid" ) == TF_WEAPON_REVOLVER )
  391. {
  392. if ( FStrEq( event->GetString( "weapon_logclassname", "" ), "ambassador" ) )
  393. {
  394. IncrementCount();
  395. }
  396. }
  397. }
  398. }
  399. };
  400. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyAmbassadorGrind, ACHIEVEMENT_TF_SPY_AMBASSADOR_GRIND, "TF_SPY_AMBASSADOR_GRIND", 5 );
  401. //----------------------------------------------------------------------------------------------------------------
  402. class CAchievementTFSpy_SpyAmbassadorSniperGrind : public CBaseTFAchievement
  403. {
  404. void Init()
  405. {
  406. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  407. SetGoal( 20 );
  408. SetStoreProgressInSteam( true );
  409. }
  410. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  411. {
  412. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  413. {
  414. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  415. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SNIPER ) )
  416. {
  417. if ( event->GetInt( "weaponid" ) == TF_WEAPON_REVOLVER )
  418. {
  419. if ( FStrEq( event->GetString( "weapon_logclassname", "" ), "ambassador" ) )
  420. {
  421. if ( IsHeadshot( event->GetInt( "customkill" ) ) )
  422. {
  423. IncrementCount();
  424. }
  425. }
  426. }
  427. }
  428. }
  429. }
  430. };
  431. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyAmbassadorSniperGrind, ACHIEVEMENT_TF_SPY_AMBASSADOR_SNIPER_GRIND, "TF_SPY_AMBASSADOR_SNIPER_GRIND", 5 );
  432. //----------------------------------------------------------------------------------------------------------------
  433. class CAchievementTFSpy_SpyAmbassadorScoutGrind : public CBaseTFAchievement
  434. {
  435. void Init()
  436. {
  437. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  438. SetGoal( 3 );
  439. SetStoreProgressInSteam( true );
  440. }
  441. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  442. {
  443. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  444. {
  445. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  446. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SCOUT ) )
  447. {
  448. if ( event->GetInt( "weaponid" ) == TF_WEAPON_REVOLVER )
  449. {
  450. if ( FStrEq( event->GetString( "weapon_logclassname", "" ), "ambassador" ) )
  451. {
  452. if ( IsHeadshot( event->GetInt( "customkill" ) ) )
  453. {
  454. IncrementCount();
  455. }
  456. }
  457. }
  458. }
  459. }
  460. }
  461. };
  462. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyAmbassadorScoutGrind, ACHIEVEMENT_TF_SPY_AMBASSADOR_SCOUT_GRIND, "TF_SPY_AMBASSADOR_SCOUT_GRIND", 5 );
  463. //----------------------------------------------------------------------------------------------------------------
  464. class CAchievementTFSpy_SpyMedicHealingKillEnemy : public CBaseTFAchievement
  465. {
  466. void Init()
  467. {
  468. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  469. SetGoal( 1 );
  470. }
  471. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  472. {
  473. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  474. {
  475. for ( int i = 1 ; i <= gpGlobals->maxClients ; i++ )
  476. {
  477. CTFPlayer *pTFPlayer = ToTFPlayer( UTIL_PlayerByIndex( i ) );
  478. // can't kill the enemy medic that's healing you for this one...should be a different enemy
  479. if ( pTFPlayer && ( pTFPlayer != pAttacker ) && ( pTFPlayer != pVictim ) )
  480. {
  481. // make sure they're not on our team
  482. if ( pAttacker->GetTeamNumber() != pTFPlayer->GetTeamNumber() )
  483. {
  484. // are they a medic that's healing me?
  485. if ( pTFPlayer->IsPlayerClass( TF_CLASS_MEDIC ) && pTFPlayer->MedicGetHealTarget() == pAttacker )
  486. {
  487. IncrementCount();
  488. }
  489. }
  490. }
  491. }
  492. }
  493. }
  494. };
  495. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyMedicHealingKillEnemy, ACHIEVEMENT_TF_SPY_MEDIC_HEALING_KILL_ENEMY, "TF_SPY_MEDIC_HEALING_KILL_ENEMY", 5 );
  496. //----------------------------------------------------------------------------------------------------------------
  497. class CAchievementTFSpy_SpyBackstabQuickKills : public CBaseTFAchievement
  498. {
  499. void Init()
  500. {
  501. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  502. SetGoal( 1 );
  503. }
  504. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  505. {
  506. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  507. {
  508. int customkill = event->GetInt( "customkill" );
  509. if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
  510. {
  511. int iNewIndex = m_Times.AddToTail();
  512. m_Times[iNewIndex] = gpGlobals->curtime;
  513. // we only care about the last three times we backstabbed someone
  514. if ( m_Times.Count() > 3 )
  515. {
  516. m_Times.Remove( 0 );
  517. }
  518. if ( m_Times.Count() == 3 )
  519. {
  520. if ( m_Times.Tail() - m_Times.Head() <= 10.0 )
  521. {
  522. IncrementCount();
  523. }
  524. }
  525. }
  526. }
  527. }
  528. private:
  529. CUtlVector< float > m_Times;
  530. };
  531. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabQuickKills, ACHIEVEMENT_TF_SPY_BACKSTAB_QUICK_KILLS, "TF_SPY_BACKSTAB_QUICK_KILLS", 5 );
  532. //----------------------------------------------------------------------------------------------------------------
  533. class CAchievementTFSpy_SpyTauntKill : public CBaseTFAchievement
  534. {
  535. void Init()
  536. {
  537. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  538. SetGoal( 1 );
  539. }
  540. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  541. {
  542. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  543. {
  544. // we already know we killed a player because of the ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS flag
  545. // was this a taunt kill?
  546. if ( event->GetInt( "customkill" ) == TF_DMG_CUSTOM_TAUNTATK_FENCING )
  547. {
  548. IncrementCount();
  549. }
  550. }
  551. }
  552. };
  553. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyTauntKill, ACHIEVEMENT_TF_SPY_TAUNT_KILL, "TF_SPY_TAUNT_KILL", 5 );
  554. //----------------------------------------------------------------------------------------------------------------
  555. class CAchievementTFSpy_SpyBackstabCappingEnemies : public CBaseTFAchievement
  556. {
  557. void Init()
  558. {
  559. SetFlags( ACH_SAVE_GLOBAL );
  560. SetGoal( 50 );
  561. SetStoreProgressInSteam( true );
  562. }
  563. // server awards this achievement, no other code within achievement necessary
  564. };
  565. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabCappingEnemies, ACHIEVEMENT_TF_SPY_BACKSTAB_CAPPING_ENEMIES, "TF_SPY_BACKSTAB_CAPPING_ENEMIES", 5 );
  566. //----------------------------------------------------------------------------------------------------------------
  567. class CAchievementTFSpy_SpyKillCPDefenders : public CBaseTFAchievement
  568. {
  569. void Init()
  570. {
  571. SetFlags( ACH_SAVE_GLOBAL );
  572. SetGoal( 15 );
  573. SetStoreProgressInSteam( true );
  574. }
  575. // server awards this achievement, no other code within achievement necessary
  576. };
  577. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyKillCPDefenders, ACHIEVEMENT_TF_SPY_KILL_CP_DEFENDERS, "TF_SPY_KILL_CP_DEFENDERS", 5 );
  578. //----------------------------------------------------------------------------------------------------------------
  579. //FYI I'm a spy
  580. //----------------------------------------------------------------------------------------------------------------
  581. class CAchievementTFSpy_FYIMedic : public CBaseTFAchievement
  582. {
  583. void Init()
  584. {
  585. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_KILL_EVENTS );
  586. SetGoal( 1 );
  587. m_hTargets.Purge();
  588. }
  589. virtual void ListenForEvents( void )
  590. {
  591. ListenForGameEvent( "player_healedbymedic" );
  592. }
  593. void FireGameEvent_Internal( IGameEvent *event )
  594. {
  595. if ( FStrEq( event->GetName(), "player_healedbymedic" ) )
  596. {
  597. int iEntity = event->GetInt( "medic" );
  598. int iMedic = GetTargetIndex( UTIL_PlayerByIndex( iEntity ) );
  599. if ( iMedic == -1 )
  600. {
  601. AddNewTarget( UTIL_PlayerByIndex( iEntity ) );
  602. }
  603. else
  604. {
  605. m_hTargets[iMedic].flRemoveTime = gpGlobals->curtime + 5.0f;
  606. }
  607. }
  608. }
  609. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  610. {
  611. if ( pAttacker == C_TFPlayer::GetLocalTFPlayer() )
  612. {
  613. int iMedic = GetTargetIndex( pVictim );
  614. if ( iMedic != -1 )
  615. {
  616. if ( m_hTargets[iMedic].flRemoveTime >= gpGlobals->curtime )
  617. {
  618. IncrementCount();
  619. }
  620. m_hTargets.Remove( iMedic );
  621. }
  622. }
  623. }
  624. int GetTargetIndex( CBaseEntity *pTarget )
  625. {
  626. for ( int i = 0; i < m_hTargets.Count(); i++ )
  627. {
  628. if ( m_hTargets[i].hTarget == pTarget )
  629. return i;
  630. }
  631. return -1;
  632. }
  633. void AddNewTarget( CBaseEntity *pTarget )
  634. {
  635. if ( !pTarget )
  636. return;
  637. // see if the target is already in our list or get a new index
  638. int iMedic = GetTargetIndex( pTarget );
  639. if ( iMedic == -1 )
  640. {
  641. iMedic = m_hTargets.AddToTail();
  642. }
  643. m_hTargets[iMedic].hTarget = pTarget;
  644. m_hTargets[iMedic].flRemoveTime = gpGlobals->curtime + 5.0f;
  645. }
  646. private:
  647. struct targets_t
  648. {
  649. EHANDLE hTarget;
  650. float flRemoveTime;
  651. };
  652. CUtlVector<targets_t> m_hTargets;
  653. };
  654. DECLARE_ACHIEVEMENT( CAchievementTFSpy_FYIMedic, ACHIEVEMENT_TF_SPY_BACKSTAB_MEDIC_HEALING_YOU, "TF_SPY_BACKSTAB_MEDIC_HEALING_YOU", 5 );
  655. //----------------------------------------------------------------------------------------------------------------
  656. // Backstab a medic/heavy pair
  657. // NOTE: Enough of this, this should be a shared achievement class.
  658. //----------------------------------------------------------------------------------------------------------------
  659. class CAchievementTFSpy_KillMedicPair : public CBaseTFAchievement
  660. {
  661. void Init()
  662. {
  663. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_KILL_ENEMY_EVENTS );
  664. SetGoal( 1 );
  665. }
  666. virtual void ListenForEvents( void )
  667. {
  668. ListenForGameEvent( "localplayer_respawn" );
  669. ListenForGameEvent( "teamplay_round_active" );
  670. m_hTargets.Purge();
  671. }
  672. void FireGameEvent_Internal( IGameEvent *event )
  673. {
  674. const char *pszEventName = event->GetName();
  675. if ( FStrEq( pszEventName, "localplayer_respawn" ) ||
  676. FStrEq( pszEventName, "teamplay_round_active" ) )
  677. {
  678. m_hTargets.Purge();
  679. }
  680. }
  681. int GetTargetIndex( CBaseEntity *pTarget )
  682. {
  683. for ( int i = 0; i < m_hTargets.Count(); i++ )
  684. {
  685. if ( m_hTargets[i].hTarget == pTarget )
  686. return i;
  687. }
  688. return -1;
  689. }
  690. void AddNewTarget( CBaseEntity *pTarget )
  691. {
  692. if ( !pTarget )
  693. return;
  694. // see if the target is already in our list or get a new index
  695. int iTargetIndex = GetTargetIndex( pTarget );
  696. if ( iTargetIndex == -1 )
  697. {
  698. iTargetIndex = m_hTargets.AddToTail();
  699. }
  700. m_hTargets[iTargetIndex].hTarget = pTarget;
  701. m_hTargets[iTargetIndex].flTimeToBeat = gpGlobals->curtime + 10.0f; // 10 seconds to kill the target
  702. }
  703. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  704. {
  705. if ( !pVictim || !pVictim->IsPlayer() )
  706. return;
  707. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  708. int customkill = event->GetInt( "customkill" );
  709. if ( pLocalPlayer == pAttacker && customkill == TF_DMG_CUSTOM_BACKSTAB )
  710. {
  711. // is this victim in our list of targets?
  712. int index = GetTargetIndex( pVictim );
  713. if ( index != -1 )
  714. {
  715. // did we beat the time?
  716. if ( m_hTargets[index].flTimeToBeat > gpGlobals->curtime )
  717. {
  718. IncrementCount();
  719. }
  720. }
  721. else
  722. {
  723. C_TFPlayer *pNewTarget = NULL;
  724. C_TFPlayer *pTFVictim = ToTFPlayer( pVictim );
  725. if ( !pTFVictim->IsPlayerClass( TF_CLASS_MEDIC ) )
  726. {
  727. for ( int i = 1 ; i <= gpGlobals->maxClients ; i++ )
  728. {
  729. pNewTarget = ToTFPlayer( UTIL_PlayerByIndex( i ) );
  730. if ( pNewTarget && pNewTarget->IsPlayerClass( TF_CLASS_MEDIC ) && pNewTarget->MedicGetHealTarget() == pTFVictim )
  731. {
  732. // add all of his Medics to our list of targets (could be more than one Medic)
  733. AddNewTarget( pNewTarget );
  734. }
  735. }
  736. }
  737. else
  738. {
  739. pNewTarget = ToTFPlayer( pTFVictim->MedicGetHealTarget() );
  740. if ( pNewTarget )
  741. {
  742. AddNewTarget( pNewTarget );
  743. }
  744. }
  745. }
  746. }
  747. // is this victim in our list of targets?
  748. int index_ = GetTargetIndex( pVictim );
  749. if ( index_ != -1 )
  750. {
  751. m_hTargets.Remove( index_ );
  752. }
  753. }
  754. private:
  755. struct targets_t
  756. {
  757. EHANDLE hTarget;
  758. float flTimeToBeat;
  759. };
  760. CUtlVector<targets_t> m_hTargets;
  761. };
  762. DECLARE_ACHIEVEMENT( CAchievementTFSpy_KillMedicPair, ACHIEVEMENT_TF_SPY_BACKSTAB_MEDIC_PAIR, "TF_SPY_BACKSTAB_MEDIC_PAIR", 5 );
  763. //----------------------------------------------------------------------------------------------------------------
  764. //Destroy 3 enemy sentries
  765. //----------------------------------------------------------------------------------------------------------------
  766. class CAchievementTFSpy_SapBuildingGrind : public CBaseTFAchievement
  767. {
  768. void Init()
  769. {
  770. SetFlags( ACH_SAVE_GLOBAL );
  771. SetGoal( 1000 );
  772. SetStoreProgressInSteam( true );
  773. }
  774. virtual void ListenForEvents()
  775. {
  776. ListenForGameEvent( "object_destroyed" );
  777. }
  778. void FireGameEvent_Internal( IGameEvent *event )
  779. {
  780. if ( Q_strcmp( event->GetName(), "object_destroyed" ) == 0 )
  781. {
  782. int iIndex = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
  783. if ( iIndex == GetLocalPlayerIndex() )
  784. {
  785. const char *pWeapon = event->GetString( "weapon" );
  786. if ( FStrEq( "obj_attachment_sapper", pWeapon ) )
  787. {
  788. IncrementCount();
  789. }
  790. }
  791. }
  792. }
  793. };
  794. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SapBuildingGrind, ACHIEVEMENT_TF_SPY_SAPPER_GRIND, "TF_SPY_SAPPER_GRIND", 5 );
  795. //----------------------------------------------------------------------------------------------------------------
  796. //Kill whoever triggered your feign death
  797. //----------------------------------------------------------------------------------------------------------------
  798. class CAchievementTFSpy_FeignDeathKill : public CBaseTFAchievement
  799. {
  800. void Init()
  801. {
  802. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  803. SetGoal( 1 );
  804. m_iKillerIndex = 0;
  805. m_flTriggerTime = gpGlobals->curtime;
  806. }
  807. virtual void ListenForEvents()
  808. {
  809. ListenForGameEvent( "player_death" );
  810. }
  811. void FireGameEvent_Internal( IGameEvent *event )
  812. {
  813. if ( Q_strcmp( event->GetName(), "player_death" ) == 0 )
  814. {
  815. int iAttacker = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
  816. int iVictim = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
  817. if ( iVictim == GetLocalPlayerIndex() )
  818. {
  819. //Someone popped my feign death
  820. if ( event->GetInt( "death_flags" ) & TF_DEATH_FEIGN_DEATH )
  821. {
  822. m_iKillerIndex = iAttacker;
  823. m_flTriggerTime = gpGlobals->curtime + 20.0f;
  824. }
  825. }
  826. }
  827. }
  828. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  829. {
  830. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  831. {
  832. C_TFPlayer *pTFVictim = ToTFPlayer( pVictim );
  833. if ( pTFVictim && pTFVictim->entindex() == m_iKillerIndex && m_flTriggerTime >= gpGlobals->curtime )
  834. {
  835. IncrementCount();
  836. }
  837. }
  838. }
  839. private:
  840. int m_iKillerIndex;
  841. float m_flTriggerTime;
  842. };
  843. DECLARE_ACHIEVEMENT( CAchievementTFSpy_FeignDeathKill, ACHIEVEMENT_TF_SPY_FEIGN_DEATH_KILL, "TF_SPY_FEIGN_DEATH_KILL", 5 );
  844. //----------------------------------------------------------------------------------------------------------------
  845. //Kill a sniper after breaking his shield
  846. //----------------------------------------------------------------------------------------------------------------
  847. class CAchievementTFSpy_ShieldKill : public CBaseTFAchievement
  848. {
  849. void Init()
  850. {
  851. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  852. SetGoal( 1 );
  853. m_iBlockerIndex = 0;
  854. m_flAttackTime = 0.0f;
  855. }
  856. virtual void ListenForEvents( void )
  857. {
  858. ListenForGameEvent( "player_shield_blocked" );
  859. }
  860. void FireGameEvent_Internal( IGameEvent *event )
  861. {
  862. if ( FStrEq( event->GetName(), "player_shield_blocked" ) )
  863. {
  864. int iAttacker = event->GetInt( "attacker_entindex" );
  865. int iBlocker = event->GetInt( "blocker_entindex" );
  866. if ( GetLocalPlayerIndex() != iAttacker )
  867. return;
  868. m_iBlockerIndex = iBlocker;
  869. m_flAttackTime = gpGlobals->curtime + 10.0f;
  870. }
  871. }
  872. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  873. {
  874. if ( m_flAttackTime <= gpGlobals->curtime )
  875. {
  876. m_iBlockerIndex = 0;
  877. return;
  878. }
  879. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  880. if ( pTFVictim && pTFVictim->entindex() == m_iBlockerIndex && pAttacker == C_TFPlayer::GetLocalTFPlayer() )
  881. {
  882. IncrementCount();
  883. }
  884. }
  885. private:
  886. int m_iBlockerIndex;
  887. float m_flAttackTime;
  888. };
  889. DECLARE_ACHIEVEMENT( CAchievementTFSpy_ShieldKill, ACHIEVEMENT_TF_SPY_BREAK_SHIELD_KILL_SNIPER, "TF_SPY_BREAK_SHIELD_KILL_SNIPER", 5 );
  890. //----------------------------------------------------------------------------------------------------------------
  891. class CAchievementTFSpy_KillWorkingEngineer : public CBaseTFAchievement
  892. {
  893. void Init()
  894. {
  895. SetFlags( ACH_SAVE_GLOBAL );
  896. SetGoal( 1 );
  897. SetStoreProgressInSteam( true );
  898. }
  899. // server awards this achievement, no other code within achievement necessary
  900. };
  901. DECLARE_ACHIEVEMENT( CAchievementTFSpy_KillWorkingEngineer, ACHIEVEMENT_TF_SPY_KILL_WORKING_ENGY, "TF_SPY_KILL_WORKING_ENGY", 5 );
  902. //----------------------------------------------------------------------------------------------------------------
  903. class CAchievementTFSpy_TFSpySurviveBurning : public CBaseTFAchievement
  904. {
  905. void Init()
  906. {
  907. SetFlags( ACH_SAVE_GLOBAL );
  908. SetGoal( 1 );
  909. m_bIsThinking = false;
  910. }
  911. virtual void ListenForEvents()
  912. {
  913. ListenForGameEvent( "player_damaged" );
  914. ListenForGameEvent( "teamplay_round_start" );
  915. ListenForGameEvent( "localplayer_respawn" );
  916. m_bIsThinking = false;
  917. }
  918. void FireGameEvent_Internal( IGameEvent *event )
  919. {
  920. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  921. if ( !pLocalPlayer )
  922. return;
  923. const char *pszEventName = event->GetName();
  924. if ( FStrEq( pszEventName, "localplayer_respawn" ) || FStrEq( pszEventName, "teamplay_round_active" ) )
  925. {
  926. ClearThink();
  927. m_bIsThinking = false;
  928. return;
  929. }
  930. // Have I taken damage?
  931. if ( FStrEq( pszEventName, "player_damaged" ))
  932. {
  933. int iDmgType = event->GetInt( "type" );
  934. // Did I survive the damage event?
  935. if ( pLocalPlayer->IsAlive() && !m_bIsThinking )
  936. {
  937. // Am I on fire?
  938. if ( (iDmgType & DMG_IGNITE) )
  939. {
  940. // Am I cloaked?
  941. if ( pLocalPlayer->m_Shared.InCond ( TF_COND_STEALTHED ) )
  942. {
  943. SetNextThink( 30 );
  944. m_bIsThinking = true;
  945. }
  946. }
  947. }
  948. }
  949. }
  950. virtual void Think( void )
  951. {
  952. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  953. if ( pLocalPlayer && pLocalPlayer->IsAlive())
  954. {
  955. IncrementCount();
  956. }
  957. }
  958. private:
  959. bool m_bIsThinking;
  960. };
  961. DECLARE_ACHIEVEMENT( CAchievementTFSpy_TFSpySurviveBurning, ACHIEVEMENT_TF_SPY_SURVIVE_BURNING, "TF_SPY_SURVIVE_BURNING", 5 );
  962. //----------------------------------------------------------------------------------------------------------------
  963. class CAchievementTFSpy_SpyBackstabEnemySwitchPyro : public CBaseTFAchievementSimple
  964. {
  965. void Init()
  966. {
  967. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  968. SetGoal( 1 );
  969. ResetBackstabbedPlayers();
  970. }
  971. virtual void ListenForEvents()
  972. {
  973. ListenForGameEvent( "player_spawn" );
  974. ListenForGameEvent( "localplayer_changeclass" );
  975. ListenForGameEvent( "localplayer_changeteam" );
  976. }
  977. void ResetBackstabbedPlayers( void )
  978. {
  979. m_BackstabbedPlayers.Purge();
  980. }
  981. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  982. {
  983. // no progress in endround
  984. if ( !GameRulesAllowsAchievements() )
  985. return;
  986. if ( !IsLocalTFPlayerClass( TF_CLASS_SPY ) )
  987. return;
  988. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  989. {
  990. int customkill = event->GetInt( "customkill" );
  991. if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
  992. {
  993. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  994. if ( pTFVictim && !pTFVictim->IsPlayerClass( TF_CLASS_PYRO ) ) // they can't already be a pyro for this one
  995. {
  996. int nUserID = pTFVictim->GetUserID();
  997. if ( m_BackstabbedPlayers.Find( nUserID ) == m_BackstabbedPlayers.InvalidIndex() )
  998. {
  999. // they're not in our list yet, add them
  1000. m_BackstabbedPlayers.AddToTail( nUserID );
  1001. }
  1002. }
  1003. }
  1004. }
  1005. }
  1006. void FireGameEvent_Internal( IGameEvent *event )
  1007. {
  1008. const char *pszEventName = event->GetName();
  1009. if ( FStrEq( pszEventName, "player_spawn" ) )
  1010. {
  1011. // no progress in endround
  1012. if ( !GameRulesAllowsAchievements() )
  1013. return;
  1014. if ( !IsLocalTFPlayerClass( TF_CLASS_SPY ) )
  1015. return;
  1016. const int nUserID = event->GetInt( "userid" );
  1017. int iIndex = m_BackstabbedPlayers.Find( nUserID );
  1018. if ( iIndex != m_BackstabbedPlayers.InvalidIndex() )
  1019. {
  1020. const int nTeam = event->GetInt( "team" );
  1021. if ( nTeam != GetLocalPlayerTeam() )
  1022. {
  1023. const int nClass = event->GetInt( "class" );
  1024. if ( nClass == TF_CLASS_PYRO )
  1025. {
  1026. IncrementCount();
  1027. }
  1028. }
  1029. m_BackstabbedPlayers.Remove( iIndex );
  1030. }
  1031. }
  1032. else if ( FStrEq( pszEventName, "localplayer_changeclass" ) ||
  1033. FStrEq( pszEventName, "localplayer_changeteam" ) )
  1034. {
  1035. ResetBackstabbedPlayers();
  1036. }
  1037. }
  1038. private:
  1039. CUtlVector< int > m_BackstabbedPlayers;
  1040. };
  1041. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabEnemySwitchPyro, ACHIEVEMENT_TF_SPY_BACKSTAB_ENEMY_SWITCH_PYRO, "TF_SPY_BACKSTAB_ENEMY_SWITCH_PYRO", 5 );
  1042. //----------------------------------------------------------------------------------------------------------------
  1043. class CAchievementTFSpy_SpyBackstabEngySapBuilding : public CBaseTFAchievement
  1044. {
  1045. void Init()
  1046. {
  1047. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  1048. SetGoal( 1 );
  1049. m_hTargets.Purge();
  1050. }
  1051. virtual void ListenForEvents()
  1052. {
  1053. ListenForGameEvent( "player_sapped_object" );
  1054. }
  1055. int FindEngyInList( CBaseEntity *pTarget )
  1056. {
  1057. for ( int i = 0; i < m_hTargets.Count(); i++ )
  1058. {
  1059. if ( m_hTargets[i].hEngy == pTarget )
  1060. return i;
  1061. }
  1062. return -1;
  1063. }
  1064. int CountSappedObjects( int iIndex )
  1065. {
  1066. int nCount = 0;
  1067. if ( m_hTargets.IsValidIndex( iIndex ) )
  1068. {
  1069. if ( m_hTargets[iIndex].bSentry )
  1070. {
  1071. nCount++;
  1072. }
  1073. if ( m_hTargets[iIndex].bDispenser )
  1074. {
  1075. nCount++;
  1076. }
  1077. if ( m_hTargets[iIndex].bTele )
  1078. {
  1079. nCount++;
  1080. }
  1081. }
  1082. return nCount;
  1083. }
  1084. void SetObjectSapped( int iIndex, int nType )
  1085. {
  1086. if ( m_hTargets.IsValidIndex( iIndex ) )
  1087. {
  1088. switch( nType )
  1089. {
  1090. case OBJ_SENTRYGUN:
  1091. m_hTargets[iIndex].bSentry = true;
  1092. break;
  1093. case OBJ_DISPENSER:
  1094. m_hTargets[iIndex].bDispenser = true;
  1095. break;
  1096. case OBJ_TELEPORTER:
  1097. m_hTargets[iIndex].bTele = true;
  1098. break;
  1099. }
  1100. }
  1101. }
  1102. void CheckAchievementEarned( void )
  1103. {
  1104. for ( int i = m_hTargets.Count() - 1; i >= 0; i-- )
  1105. {
  1106. if ( m_hTargets[i].flTimeToBeat < gpGlobals->curtime )
  1107. {
  1108. // time has run out on this one
  1109. m_hTargets.Remove( i );
  1110. }
  1111. else
  1112. {
  1113. if ( CountSappedObjects( i ) >= 3 )
  1114. {
  1115. IncrementCount();
  1116. m_hTargets.Purge();
  1117. return;
  1118. }
  1119. }
  1120. }
  1121. }
  1122. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1123. {
  1124. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  1125. {
  1126. int customkill = event->GetInt( "customkill" );
  1127. if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
  1128. {
  1129. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  1130. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_ENGINEER ) )
  1131. {
  1132. int iIndex = FindEngyInList( pVictim );
  1133. if ( iIndex == -1 )
  1134. {
  1135. iIndex = m_hTargets.AddToTail();
  1136. }
  1137. m_hTargets[iIndex].hEngy = pVictim;
  1138. m_hTargets[iIndex].bSentry = false;
  1139. m_hTargets[iIndex].bDispenser = false;
  1140. m_hTargets[iIndex].bTele = false;
  1141. m_hTargets[iIndex].flTimeToBeat = gpGlobals->curtime + 10.0;
  1142. }
  1143. }
  1144. CheckAchievementEarned(); // checks the achievement list, but also cleans out old entries (based on flTimeToBeat)
  1145. }
  1146. }
  1147. void FireGameEvent_Internal( IGameEvent *event )
  1148. {
  1149. const char *pszEventName = event->GetName();
  1150. if ( FStrEq( pszEventName, "player_sapped_object" ) )
  1151. {
  1152. int nUserID = event->GetInt( "userid" );
  1153. CBasePlayer *pPlayer = UTIL_PlayerByIndex( engine->GetPlayerForUserID( nUserID ) );
  1154. if ( pPlayer == C_BasePlayer::GetLocalPlayer() )
  1155. {
  1156. CBasePlayer *pEngy = UTIL_PlayerByIndex( engine->GetPlayerForUserID( event->GetInt( "ownerid" ) ) );
  1157. int iIndex = FindEngyInList( pEngy );
  1158. if ( iIndex != -1 )
  1159. {
  1160. SetObjectSapped( iIndex, event->GetInt( "object" ) );
  1161. }
  1162. CheckAchievementEarned(); // checks the achievement list, but also cleans out old entries (based on flTimeToBeat)
  1163. }
  1164. }
  1165. }
  1166. private:
  1167. struct targets_t
  1168. {
  1169. EHANDLE hEngy;
  1170. bool bSentry;
  1171. bool bDispenser;
  1172. bool bTele;
  1173. float flTimeToBeat;
  1174. };
  1175. CUtlVector<targets_t> m_hTargets;
  1176. };
  1177. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabEngySapBuilding, ACHIEVEMENT_TF_SPY_BACKSTAB_ENGY_SAP_BUILDING, "TF_SPY_BACKSTAB_ENGY_SAP_BUILDING", 5 );
  1178. //----------------------------------------------------------------------------------------------------------------
  1179. class CAchievementTFSpy_SpySapBuildingBackstabEngy : public CBaseTFAchievement
  1180. {
  1181. void Init()
  1182. {
  1183. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  1184. SetGoal( 1 );
  1185. m_hTargets.Purge();
  1186. }
  1187. virtual void ListenForEvents()
  1188. {
  1189. ListenForGameEvent( "player_sapped_object" );
  1190. }
  1191. int FindEngyInList( CBaseEntity *pTarget )
  1192. {
  1193. for ( int i = 0; i < m_hTargets.Count(); i++ )
  1194. {
  1195. if ( m_hTargets[i].hEngy == pTarget )
  1196. return i;
  1197. }
  1198. return -1;
  1199. }
  1200. void ValidateList( void )
  1201. {
  1202. for ( int i = m_hTargets.Count() - 1; i >= 0; i-- )
  1203. {
  1204. if ( m_hTargets[i].flTimeToBeat < gpGlobals->curtime )
  1205. {
  1206. // time has run out on this one
  1207. m_hTargets.Remove( i );
  1208. }
  1209. }
  1210. }
  1211. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1212. {
  1213. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  1214. {
  1215. int customkill = event->GetInt( "customkill" );
  1216. if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
  1217. {
  1218. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  1219. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_ENGINEER ) )
  1220. {
  1221. int iIndex = FindEngyInList( pVictim );
  1222. if ( iIndex != -1 )
  1223. {
  1224. // they're in our list...is the time still valid?
  1225. if ( m_hTargets[iIndex].flTimeToBeat > gpGlobals->curtime )
  1226. {
  1227. IncrementCount();
  1228. m_hTargets.Purge();
  1229. return;
  1230. }
  1231. }
  1232. }
  1233. }
  1234. ValidateList();
  1235. }
  1236. }
  1237. void FireGameEvent_Internal( IGameEvent *event )
  1238. {
  1239. const char *pszEventName = event->GetName();
  1240. if ( FStrEq( pszEventName, "player_sapped_object" ) )
  1241. {
  1242. int nUserID = event->GetInt( "userid" );
  1243. CBasePlayer *pPlayer = UTIL_PlayerByIndex( engine->GetPlayerForUserID( nUserID ) );
  1244. if ( pPlayer == C_BasePlayer::GetLocalPlayer() )
  1245. {
  1246. CBasePlayer *pEngy = UTIL_PlayerByIndex( engine->GetPlayerForUserID( event->GetInt( "ownerid" ) ) );
  1247. if ( pEngy )
  1248. {
  1249. int iIndex = FindEngyInList( pEngy );
  1250. if ( iIndex == -1 )
  1251. {
  1252. iIndex = m_hTargets.AddToTail();
  1253. }
  1254. m_hTargets[iIndex].hEngy = pEngy;
  1255. m_hTargets[iIndex].flTimeToBeat = gpGlobals->curtime + 5.0;
  1256. }
  1257. ValidateList();
  1258. }
  1259. }
  1260. }
  1261. private:
  1262. struct targets_t
  1263. {
  1264. EHANDLE hEngy;
  1265. float flTimeToBeat;
  1266. };
  1267. CUtlVector<targets_t> m_hTargets;
  1268. };
  1269. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpySapBuildingBackstabEngy, ACHIEVEMENT_TF_SPY_SAP_BUILDING_BACKSTAB_ENGY, "TF_SPY_SAP_BUILDING_BACKSTAB_ENGY", 5 );
  1270. //----------------------------------------------------------------------------------------------------------------
  1271. class CAchievementTFSpy_SapperTeamwork : public CBaseTFAchievement
  1272. {
  1273. void Init()
  1274. {
  1275. SetFlags( ACH_SAVE_GLOBAL );
  1276. SetGoal( 1 );
  1277. ResetData();
  1278. }
  1279. virtual void ListenForEvents()
  1280. {
  1281. ListenForGameEvent( "player_sapped_object" );
  1282. ListenForGameEvent( "localplayer_changeteam" );
  1283. }
  1284. void ResetData( void )
  1285. {
  1286. m_hTeammates.Purge();
  1287. m_nLocalPlayerTarget = -1;
  1288. m_flLocalPlayerTime = -1;
  1289. }
  1290. int FindSpyInList( int userid )
  1291. {
  1292. for ( int i = 0; i < m_hTeammates.Count(); i++ )
  1293. {
  1294. if ( m_hTeammates[i].nSpy == userid )
  1295. return i;
  1296. }
  1297. return -1;
  1298. }
  1299. void CheckAchievementEarned( void )
  1300. {
  1301. // has the local player sapped anything?
  1302. if ( m_nLocalPlayerTarget == -1 && m_flLocalPlayerTime == -1 )
  1303. return;
  1304. // has it been longer than 3 seconds since the local player sapped something?
  1305. if ( gpGlobals->curtime - m_flLocalPlayerTime > 3.0 )
  1306. {
  1307. // reset the local player target and time, this fixes the local player sapping something and
  1308. // then a teammate saps something > 3 seconds later (otherwise, the new entry would be removed in the for loop below)
  1309. m_nLocalPlayerTarget = -1;
  1310. m_flLocalPlayerTime = -1;
  1311. return;
  1312. }
  1313. for ( int i = m_hTeammates.Count() - 1; i >= 0; i-- )
  1314. {
  1315. if ( m_hTeammates[i].nTarget != m_nLocalPlayerTarget ) // different guns
  1316. {
  1317. if ( fabs( m_hTeammates[i].flTime - m_flLocalPlayerTime ) <= 3.0 )
  1318. {
  1319. IncrementCount();
  1320. ResetData();
  1321. return;
  1322. }
  1323. else
  1324. {
  1325. m_hTeammates.Remove( i );
  1326. }
  1327. }
  1328. }
  1329. }
  1330. void FireGameEvent_Internal( IGameEvent *event )
  1331. {
  1332. const char *pszEventName = event->GetName();
  1333. if ( FStrEq( pszEventName, "player_sapped_object" ) )
  1334. {
  1335. if ( event->GetInt( "object" ) == OBJ_SENTRYGUN )
  1336. {
  1337. int nUserID = event->GetInt( "userid" );
  1338. CTFPlayer *pSpy = ToTFPlayer( UTIL_PlayerByIndex( engine->GetPlayerForUserID( nUserID ) ) );
  1339. if ( pSpy && pSpy->GetTeamNumber() == GetLocalPlayerTeam() )
  1340. {
  1341. if ( pSpy == C_BasePlayer::GetLocalPlayer() )
  1342. {
  1343. m_nLocalPlayerTarget = event->GetInt( "ownerid" );
  1344. m_flLocalPlayerTime = gpGlobals->curtime;
  1345. }
  1346. else
  1347. {
  1348. int iIndex = FindSpyInList( nUserID );
  1349. if ( iIndex == -1 )
  1350. {
  1351. iIndex = m_hTeammates.AddToTail();
  1352. }
  1353. m_hTeammates[iIndex].nSpy = nUserID;
  1354. m_hTeammates[iIndex].nTarget = event->GetInt( "ownerid" );
  1355. m_hTeammates[iIndex].flTime = gpGlobals->curtime;
  1356. }
  1357. CheckAchievementEarned(); // checks the achievement list, but also cleans out old entries (based on time)
  1358. }
  1359. }
  1360. }
  1361. else if ( FStrEq( pszEventName, "localplayer_changeteam" ) )
  1362. {
  1363. ResetData();
  1364. }
  1365. }
  1366. private:
  1367. struct teammates_t
  1368. {
  1369. int nSpy; // who built the sapper
  1370. int nTarget; // owner of the gun
  1371. float flTime; // time it was sapped
  1372. };
  1373. CUtlVector<teammates_t> m_hTeammates; // list of teammates who have sapped guns
  1374. int m_nLocalPlayerTarget; // owner of the gun
  1375. float m_flLocalPlayerTime; // time it was sapped
  1376. };
  1377. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SapperTeamwork, ACHIEVEMENT_TF_SPY_SAPPER_TEAMWORK, "TF_SPY_SAPPER_TEAMWORK", 5 );
  1378. //----------------------------------------------------------------------------------------------------------------
  1379. class CAchievementTFSpy_SpyCampPosition : public CBaseTFAchievement
  1380. {
  1381. void Init()
  1382. {
  1383. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  1384. SetGoal( 1 );
  1385. ResetData();
  1386. }
  1387. void ResetData()
  1388. {
  1389. m_hTargets.Purge();
  1390. }
  1391. virtual void ListenForEvents( void )
  1392. {
  1393. ListenForGameEvent( "localplayer_respawn" );
  1394. ListenForGameEvent( "teamplay_round_active" );
  1395. ResetData();
  1396. }
  1397. int FindEnemyInList( CBaseEntity *pTarget )
  1398. {
  1399. for ( int i = 0; i < m_hTargets.Count(); i++ )
  1400. {
  1401. if ( m_hTargets[i].hEnemy == pTarget )
  1402. return i;
  1403. }
  1404. return -1;
  1405. }
  1406. void FireGameEvent_Internal( IGameEvent *event )
  1407. {
  1408. const char *pszEventName = event->GetName();
  1409. if ( FStrEq( pszEventName, "localplayer_respawn" ) ||
  1410. FStrEq( pszEventName, "teamplay_round_active" ) )
  1411. {
  1412. ResetData();
  1413. }
  1414. }
  1415. bool LocalPlayerHasMotionCloakEquipped( void )
  1416. {
  1417. CTFPlayer *pPlayer = ToTFPlayer( C_BasePlayer::GetLocalPlayer() );
  1418. if ( pPlayer )
  1419. {
  1420. CTFWeaponInvis *pWeapon = (CTFWeaponInvis *) pPlayer->Weapon_OwnsThisID( TF_WEAPON_INVIS );
  1421. if ( pWeapon && pWeapon->HasMotionCloak() )
  1422. {
  1423. return true;
  1424. }
  1425. }
  1426. return false;
  1427. }
  1428. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1429. {
  1430. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  1431. {
  1432. if ( LocalPlayerHasMotionCloakEquipped() )
  1433. {
  1434. int iIndex = FindEnemyInList( pVictim );
  1435. if ( iIndex != -1 )
  1436. {
  1437. // they're already in our list
  1438. Vector vecOrigin = pVictim->GetAbsOrigin();
  1439. if ( ( m_hTargets[iIndex].vecOrigin - vecOrigin ).LengthSqr() > (1024*1024) )
  1440. {
  1441. // we killed them too far away from our last position, so reset
  1442. m_hTargets[iIndex].nKillCount = 1;
  1443. m_hTargets[iIndex].vecOrigin = vecOrigin;
  1444. }
  1445. else
  1446. {
  1447. // they were close enough, so add to our kill count
  1448. m_hTargets[iIndex].nKillCount++;
  1449. }
  1450. }
  1451. else
  1452. {
  1453. // they're new to our list
  1454. iIndex = m_hTargets.AddToTail();
  1455. m_hTargets[iIndex].hEnemy = pVictim;
  1456. m_hTargets[iIndex].nKillCount = 1;
  1457. m_hTargets[iIndex].vecOrigin = pVictim->GetAbsOrigin();
  1458. }
  1459. if ( m_hTargets[iIndex].nKillCount >= 3 )
  1460. {
  1461. IncrementCount();
  1462. ResetData();
  1463. }
  1464. }
  1465. else
  1466. {
  1467. // Not using motion cloak anymore
  1468. ResetData();
  1469. }
  1470. }
  1471. }
  1472. private:
  1473. struct targets_t
  1474. {
  1475. EHANDLE hEnemy;
  1476. int nKillCount;
  1477. Vector vecOrigin;
  1478. };
  1479. CUtlVector<targets_t> m_hTargets;
  1480. };
  1481. DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyCampPosition, ACHIEVEMENT_TF_SPY_CAMP_POSITION, "TF_SPY_CAMP_POSITION", 5 );
  1482. //----------------------------------------------------------------------------------------------------------------
  1483. class CAchievementTFSpy_AchieveProgress1 : public CAchievement_AchievedCount
  1484. {
  1485. public:
  1486. DECLARE_CLASS( CAchievementTFSpy_AchieveProgress1, CAchievement_AchievedCount );
  1487. void Init()
  1488. {
  1489. BaseClass::Init();
  1490. SetAchievementsRequired( 5, ACHIEVEMENT_TF_SPY_START_RANGE, ACHIEVEMENT_TF_SPY_END_RANGE );
  1491. }
  1492. };
  1493. DECLARE_ACHIEVEMENT( CAchievementTFSpy_AchieveProgress1, ACHIEVEMENT_TF_SPY_ACHIEVE_PROGRESS1, "TF_SPY_ACHIEVE_PROGRESS1", 5 );
  1494. //----------------------------------------------------------------------------------------------------------------
  1495. class CAchievementTFSpy_AchieveProgress2 : public CAchievement_AchievedCount
  1496. {
  1497. public:
  1498. DECLARE_CLASS( CAchievementTFSpy_AchieveProgress2, CAchievement_AchievedCount );
  1499. void Init()
  1500. {
  1501. BaseClass::Init();
  1502. SetAchievementsRequired( 11, ACHIEVEMENT_TF_SPY_START_RANGE, ACHIEVEMENT_TF_SPY_END_RANGE );
  1503. }
  1504. };
  1505. DECLARE_ACHIEVEMENT( CAchievementTFSpy_AchieveProgress2, ACHIEVEMENT_TF_SPY_ACHIEVE_PROGRESS2, "TF_SPY_ACHIEVE_PROGRESS2", 5 );
  1506. //----------------------------------------------------------------------------------------------------------------
  1507. class CAchievementTFSpy_AchieveProgress3 : public CAchievement_AchievedCount
  1508. {
  1509. public:
  1510. DECLARE_CLASS( CAchievementTFSpy_AchieveProgress3, CAchievement_AchievedCount );
  1511. void Init()
  1512. {
  1513. BaseClass::Init();
  1514. SetAchievementsRequired( 17, ACHIEVEMENT_TF_SPY_START_RANGE, ACHIEVEMENT_TF_SPY_END_RANGE );
  1515. }
  1516. };
  1517. DECLARE_ACHIEVEMENT( CAchievementTFSpy_AchieveProgress3, ACHIEVEMENT_TF_SPY_ACHIEVE_PROGRESS3, "TF_SPY_ACHIEVE_PROGRESS3", 5 );
  1518. //----------------------------------------------------------------------------------------------------------------
  1519. class CAchievementTFSpy_KillBackScatterScout : public CBaseTFAchievement
  1520. {
  1521. public:
  1522. void Init()
  1523. {
  1524. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
  1525. SetGoal( 1 );
  1526. }
  1527. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1528. {
  1529. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  1530. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SCOUT ) && ( pAttacker == C_TFPlayer::GetLocalTFPlayer() ) )
  1531. {
  1532. if ( event->GetInt( "customkill" ) == TF_DMG_CUSTOM_BACKSTAB )
  1533. {
  1534. CTFWeaponBase *pWeapon = pTFVictim->GetActiveTFWeapon();
  1535. if ( pWeapon && ( pWeapon->GetWeaponID() == TF_WEAPON_SCATTERGUN ) )
  1536. {
  1537. int iMiniCritBackAttack = 0;
  1538. CALL_ATTRIB_HOOK_INT_ON_OTHER( pWeapon, iMiniCritBackAttack, closerange_backattack_minicrits );
  1539. if ( iMiniCritBackAttack > 0 )
  1540. {
  1541. IncrementCount();
  1542. }
  1543. }
  1544. }
  1545. }
  1546. }
  1547. };
  1548. DECLARE_ACHIEVEMENT( CAchievementTFSpy_KillBackScatterScout, ACHIEVEMENT_TF_SPY_KILL_BACKSCATTER_SCOUT, "TF_SPY_KILL_BACKSCATTER_SCOUT", 5 );
  1549. #endif // CLIENT_DLL