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.

1732 lines
51 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_objective_resource.h"
  17. #include "tf_weapon_shotgun.h"
  18. //----------------------------------------------------------------------------------------------------------------
  19. class CAchievementTFScout_FirstBlood : public CBaseTFAchievement
  20. {
  21. void Init()
  22. {
  23. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  24. SetGoal( 1 );
  25. }
  26. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  27. {
  28. // Achievement for getting first blood.
  29. if ( event->GetInt( "death_flags" ) & TF_DEATH_FIRST_BLOOD )
  30. {
  31. IncrementCount();
  32. }
  33. }
  34. };
  35. DECLARE_ACHIEVEMENT( CAchievementTFScout_FirstBlood, ACHIEVEMENT_TF_SCOUT_FIRST_BLOOD, "TF_SCOUT_FIRST_BLOOD", 5 );
  36. //----------------------------------------------------------------------------------------------------------------
  37. class CAchievementTFScout_FirstBloodKill : public CBaseTFAchievement
  38. {
  39. void Init()
  40. {
  41. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  42. SetGoal( 5 );
  43. SetStoreProgressInSteam( true );
  44. }
  45. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  46. {
  47. CTFPlayer *pAttackerPlayer = ToTFPlayer( pAttacker );
  48. // Achievement for accumulating 5 kills over several matches with the first blood crit boost.
  49. bool bFirstBlood = event->GetInt( "death_flags" ) & TF_DEATH_FIRST_BLOOD;
  50. if ( pAttackerPlayer->m_Shared.IsFirstBloodBoosted() &&
  51. pAttackerPlayer->m_Shared.InCond( TF_COND_CRITBOOSTED_FIRST_BLOOD ) &&
  52. !bFirstBlood )
  53. {
  54. IncrementCount();
  55. }
  56. }
  57. };
  58. DECLARE_ACHIEVEMENT( CAchievementTFScout_FirstBloodKill, ACHIEVEMENT_TF_SCOUT_FIRST_BLOOD_KILL, "TF_SCOUT_FIRST_BLOOD_KILL", 5 );
  59. //----------------------------------------------------------------------------------------------------------------
  60. class CAchievementTFScout_WellEarlyKill : public CBaseTFAchievement
  61. {
  62. void Init()
  63. {
  64. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  65. SetGoal( 1 );
  66. }
  67. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  68. {
  69. // Achievement for getting a kill in cp_well during the setup phase.
  70. if ( FStrEq( m_pAchievementMgr->GetMapName(), "cp_well" ) &&
  71. TFGameRules() && (TFGameRules()->State_Get() == GR_STATE_RND_RUNNING) &&
  72. TFGameRules()->InSetup() )
  73. {
  74. IncrementCount();
  75. }
  76. }
  77. };
  78. DECLARE_ACHIEVEMENT( CAchievementTFScout_WellEarlyKill, ACHIEVEMENT_TF_SCOUT_WELL_EARLY_KILL, "TF_SCOUT_WELL_EARLY_KILL", 5 );
  79. //----------------------------------------------------------------------------------------------------------------
  80. class CAchievementTFScout_LifetimeKills : public CBaseTFAchievement
  81. {
  82. void Init()
  83. {
  84. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  85. SetGoal( 2004 );
  86. SetStoreProgressInSteam( true );
  87. }
  88. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  89. {
  90. // Achievement for getting 2004 lifetime kills!
  91. IncrementCount();
  92. }
  93. };
  94. DECLARE_ACHIEVEMENT( CAchievementTFScout_LifetimeKills, ACHIEVEMENT_TF_SCOUT_LIFETIME_KILLS, "TF_SCOUT_LIFETIME_KILLS", 5 );
  95. //----------------------------------------------------------------------------------------------------------------
  96. class CAchievementTFScout_IronManKills : public CBaseTFAchievement
  97. {
  98. void Init()
  99. {
  100. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  101. SetGoal( 1 );
  102. ResetTracking();
  103. }
  104. virtual void ListenForEvents( void )
  105. {
  106. ListenForGameEvent( "localplayer_respawn" );
  107. ListenForGameEvent( "teamplay_round_active" );
  108. ResetTracking();
  109. }
  110. void FireGameEvent_Internal( IGameEvent *event )
  111. {
  112. const char *pszEventName = event->GetName();
  113. if ( FStrEq( pszEventName, "localplayer_respawn" ) ||
  114. FStrEq( pszEventName, "teamplay_round_active" ) )
  115. {
  116. ResetTracking();
  117. }
  118. }
  119. void ResetTracking()
  120. {
  121. m_bKillOnGround = false;
  122. m_bKillInAir = false;
  123. m_bKillInWater = false;
  124. }
  125. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  126. {
  127. // Achievement for getting a kill while on the ground, in the air, and in the water in a single life.
  128. CTFPlayer *pAttackerPlayer = ToTFPlayer( pAttacker );
  129. if ( !pAttackerPlayer )
  130. return;
  131. if ( pAttackerPlayer->GetWaterLevel() == WL_Eyes )
  132. {
  133. m_bKillInWater = true;
  134. }
  135. else if ( !(pAttackerPlayer->GetFlags() & FL_ONGROUND) )
  136. {
  137. m_bKillInAir = true;
  138. }
  139. else
  140. {
  141. m_bKillOnGround = true;
  142. }
  143. if ( m_bKillOnGround && m_bKillInAir && m_bKillInWater )
  144. {
  145. IncrementCount();
  146. }
  147. }
  148. bool m_bKillOnGround;
  149. bool m_bKillInAir;
  150. bool m_bKillInWater;
  151. };
  152. DECLARE_ACHIEVEMENT( CAchievementTFScout_IronManKills, ACHIEVEMENT_TF_SCOUT_IRON_MAN_KILLS, "TF_SCOUT_IRON_MAN_KILLS", 5 );
  153. //----------------------------------------------------------------------------------------------------------------
  154. class CAchievementTFScout_DestroyTeleporters : public CBaseTFAchievement
  155. {
  156. void Init()
  157. {
  158. SetFlags( ACH_SAVE_GLOBAL );
  159. SetGoal( 3 );
  160. SetStoreProgressInSteam( true );
  161. }
  162. virtual void ListenForEvents()
  163. {
  164. ListenForGameEvent( "object_destroyed" );
  165. }
  166. void FireGameEvent_Internal( IGameEvent *event )
  167. {
  168. if ( Q_strcmp( event->GetName(), "object_destroyed" ) == 0 )
  169. {
  170. int iIndex = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
  171. CBaseEntity *pDestroyer = UTIL_PlayerByIndex( iIndex );
  172. C_TFPlayer *pTFPlayer = C_TFPlayer::GetLocalTFPlayer();
  173. if ( pDestroyer == pTFPlayer )
  174. {
  175. // Only count teleporters.
  176. int iType = event->GetInt( "objecttype" );
  177. if ( iType == OBJ_TELEPORTER )
  178. {
  179. IncrementCount();
  180. }
  181. }
  182. }
  183. }
  184. };
  185. DECLARE_ACHIEVEMENT( CAchievementTFScout_DestroyTeleporters, ACHIEVEMENT_TF_SCOUT_DESTROY_TELEPORTERS, "TF_SCOUT_DESTROY_TELEPORTERS", 5 );
  186. //----------------------------------------------------------------------------------------------------------------
  187. class CAchievementTFScout_DestroyBuildingsBeingBuilt : public CBaseTFAchievement
  188. {
  189. void Init()
  190. {
  191. SetFlags( ACH_SAVE_GLOBAL );
  192. SetGoal( 3 );
  193. SetStoreProgressInSteam( true );
  194. }
  195. virtual void ListenForEvents()
  196. {
  197. ListenForGameEvent( "object_destroyed" );
  198. }
  199. void FireGameEvent_Internal( IGameEvent *event )
  200. {
  201. if ( Q_strcmp( event->GetName(), "object_destroyed" ) == 0 )
  202. {
  203. int iIndex = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
  204. CBaseEntity *pDestroyer = UTIL_PlayerByIndex( iIndex );
  205. C_TFPlayer *pTFPlayer = C_TFPlayer::GetLocalTFPlayer();
  206. if ( pDestroyer == pTFPlayer )
  207. {
  208. // Only count buildings being built.
  209. if ( event->GetBool( "was_building" ) )
  210. {
  211. IncrementCount();
  212. }
  213. }
  214. }
  215. }
  216. };
  217. DECLARE_ACHIEVEMENT( CAchievementTFScout_DestroyBuildingsBeingBuilt, ACHIEVEMENT_TF_SCOUT_DESTROY_BUILDINGS_BEING_BUILT, "TF_SCOUT_DESTROY_BUILDINGS_BEING_BUILT", 5 );
  218. //----------------------------------------------------------------------------------------------------------------
  219. class CAchievementTFScout_DestroySentryWithPistol : public CBaseTFAchievement
  220. {
  221. void Init()
  222. {
  223. SetFlags( ACH_SAVE_GLOBAL );
  224. SetGoal( 1 );
  225. }
  226. virtual void ListenForEvents()
  227. {
  228. ListenForGameEvent( "object_destroyed" );
  229. }
  230. void FireGameEvent_Internal( IGameEvent *event )
  231. {
  232. if ( Q_strcmp( event->GetName(), "object_destroyed" ) == 0 )
  233. {
  234. int iIndex = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
  235. CBaseEntity *pDestroyer = UTIL_PlayerByIndex( iIndex );
  236. C_TFPlayer *pTFPlayer = C_TFPlayer::GetLocalTFPlayer();
  237. if ( pDestroyer == pTFPlayer )
  238. {
  239. // Only count active sentries destroyed with a pistol.
  240. int iType = event->GetInt( "objecttype" );
  241. int iWeaponID = event->GetInt( "weaponid" );
  242. if ( (iType == OBJ_SENTRYGUN) &&
  243. (iWeaponID == TF_WEAPON_PISTOL_SCOUT) &&
  244. !event->GetBool( "was_building" ) )
  245. {
  246. IncrementCount();
  247. }
  248. }
  249. }
  250. }
  251. };
  252. DECLARE_ACHIEVEMENT( CAchievementTFScout_DestroySentryWithPistol, ACHIEVEMENT_TF_SCOUT_DESTROY_SENTRY_WITH_PISTOL, "TF_SCOUT_DESTROY_SENTRY_WITH_PISTOL", 5 );
  253. //----------------------------------------------------------------------------------------------------------------
  254. class CAchievementTFScout_DoubleJumps : public CBaseTFAchievement
  255. {
  256. void Init()
  257. {
  258. SetFlags( ACH_SAVE_GLOBAL );
  259. SetGoal( 1000 );
  260. SetStoreProgressInSteam( true );
  261. m_bScoredJump = false;
  262. }
  263. virtual void ListenForEvents()
  264. {
  265. ListenForGameEvent( "air_dash" );
  266. ListenForGameEvent( "landed" );
  267. ListenForGameEvent( "localplayer_respawn" );
  268. ListenForGameEvent( "teamplay_round_active" );
  269. }
  270. void FireGameEvent_Internal( IGameEvent *event )
  271. {
  272. // Achievement for getting 1000 double jumps.
  273. if ( Q_strcmp( event->GetName(), "air_dash" ) == 0 )
  274. {
  275. int iJumperID = event->GetInt( "player" );
  276. C_TFPlayer *pJumper = ToTFPlayer( UTIL_PlayerByIndex( engine->GetPlayerForUserID( iJumperID ) ) );
  277. if ( pJumper == C_TFPlayer::GetLocalTFPlayer() && !m_bScoredJump )
  278. {
  279. m_bScoredJump = true;
  280. IncrementCount();
  281. }
  282. }
  283. else if ( (Q_strcmp( event->GetName(), "landed" ) == 0) ||
  284. (Q_strcmp( event->GetName(), "localplayer_respawn" ) == 0) ||
  285. (Q_strcmp( event->GetName(), "teamplay_round_active" ) == 0) )
  286. {
  287. m_bScoredJump = false;
  288. }
  289. }
  290. private:
  291. bool m_bScoredJump;
  292. };
  293. DECLARE_ACHIEVEMENT( CAchievementTFScout_DoubleJumps, ACHIEVEMENT_TF_SCOUT_DOUBLE_JUMPS, "TF_SCOUT_DOUBLE_JUMPS", 5 );
  294. //----------------------------------------------------------------------------------------------------------------
  295. class CAchievementTFScout_AssistChargeMedic : public CBaseTFAchievement
  296. {
  297. void Init()
  298. {
  299. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  300. SetGoal( 1 );
  301. m_bCharged = false;
  302. m_iAssists = 0;
  303. m_iMedic = -1;
  304. }
  305. virtual void ListenForEvents()
  306. {
  307. ListenForGameEvent( "player_chargedeployed" );
  308. }
  309. void FireGameEvent_Internal( IGameEvent *event )
  310. {
  311. if ( Q_strcmp( event->GetName(), "player_chargedeployed" ) == 0 )
  312. {
  313. m_iMedic = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
  314. CBaseEntity *pMedic = UTIL_PlayerByIndex( m_iMedic );
  315. int iTarget = engine->GetPlayerForUserID( event->GetInt( "targetid" ) );
  316. CBaseEntity *pTarget = UTIL_PlayerByIndex( iTarget );
  317. if ( pMedic && pTarget && pTarget == C_TFPlayer::GetLocalTFPlayer() )
  318. {
  319. m_bCharged = true;
  320. m_iAssists = 0;
  321. }
  322. }
  323. }
  324. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  325. {
  326. int iAssisterIndex = engine->GetPlayerForUserID( event->GetInt( "assister" ) );
  327. if ( iAssisterIndex > 0 && iAssisterIndex == m_iMedic )
  328. {
  329. C_TFPlayer *pMedic = ToTFPlayer( UTIL_PlayerByIndex( iAssisterIndex ) );
  330. if ( pMedic && pMedic->MedicIsReleasingCharge() )
  331. {
  332. m_iAssists++;
  333. if ( m_iAssists >= 3 )
  334. {
  335. IncrementCount();
  336. }
  337. }
  338. }
  339. }
  340. private:
  341. bool m_bCharged;
  342. int m_iAssists;
  343. int m_iMedic;
  344. };
  345. DECLARE_ACHIEVEMENT( CAchievementTFScout_AssistChargeMedic, ACHIEVEMENT_TF_SCOUT_ASSIST_MEDIC, "TF_SCOUT_ASSIST_MEDIC", 5 );
  346. //----------------------------------------------------------------------------------------------------------------
  347. class CAchievementTFScout_StealSandwich : public CBaseTFAchievement
  348. {
  349. void Init()
  350. {
  351. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  352. SetGoal( 1 );
  353. m_iHeavyID = -1;
  354. }
  355. virtual void ListenForEvents()
  356. {
  357. ListenForGameEvent( "player_stealsandvich" );
  358. ListenForGameEvent( "localplayer_respawn" );
  359. ListenForGameEvent( "teamplay_round_active" );
  360. }
  361. void FireGameEvent_Internal( IGameEvent *event )
  362. {
  363. const char *pszEventName = event->GetName();
  364. if ( FStrEq( pszEventName, "localplayer_respawn" ) ||
  365. FStrEq( pszEventName, "teamplay_round_active" ) )
  366. {
  367. // If we died or respawned, reset...
  368. m_iHeavyID = -1;
  369. return;
  370. }
  371. else if ( Q_strcmp( event->GetName(), "player_stealsandvich" ) == 0 )
  372. {
  373. int iOwner = engine->GetPlayerForUserID( event->GetInt( "owner" ) );
  374. if ( iOwner != m_iHeavyID )
  375. return;
  376. int iTarget = engine->GetPlayerForUserID( event->GetInt( "target" ) );
  377. CBaseEntity *pTarget = UTIL_PlayerByIndex( iTarget );
  378. if ( pTarget && pTarget == C_TFPlayer::GetLocalTFPlayer() )
  379. {
  380. IncrementCount();
  381. }
  382. }
  383. }
  384. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  385. {
  386. // Achievement for killing a Heavy and taking his sandvich.
  387. C_TFPlayer *pTFVictim = ToTFPlayer( pVictim );
  388. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_HEAVYWEAPONS ) )
  389. {
  390. // Track the heavy: we have to be responsible for his death.
  391. m_iHeavyID = engine->GetPlayerForUserID( pTFVictim->GetUserID() );
  392. }
  393. }
  394. private:
  395. int m_iHeavyID;
  396. };
  397. DECLARE_ACHIEVEMENT( CAchievementTFScout_StealSandwich, ACHIEVEMENT_TF_SCOUT_STEAL_SANDWICH, "TF_SCOUT_STEAL_SANDWICH", 5 );
  398. //----------------------------------------------------------------------------------------------------------------
  399. class CAchievementTFScout_KillChargedMedic : public CBaseTFAchievement
  400. {
  401. void Init()
  402. {
  403. SetFlags( ACH_SAVE_GLOBAL );
  404. SetGoal( 1 );
  405. }
  406. // client fires an event for this achievement, no other code within achievement necessary
  407. };
  408. DECLARE_ACHIEVEMENT( CAchievementTFScout_KillChargedMedic, ACHIEVEMENT_TF_SCOUT_KILL_CHARGED_MEDICS, "TF_SCOUT_KILL_CHARGED_MEDICS", 5 );
  409. //----------------------------------------------------------------------------------------------------------------
  410. class CAchievementTFScout_SurviveDamage : public CBaseTFAchievement
  411. {
  412. void Init()
  413. {
  414. SetFlags( ACH_SAVE_GLOBAL );
  415. SetGoal( 1 );
  416. }
  417. virtual void ListenForEvents()
  418. {
  419. ListenForGameEvent( "player_damaged" );
  420. ListenForGameEvent( "teamplay_round_active" );
  421. ListenForGameEvent( "localplayer_respawn" );
  422. m_iDamageTotal = 0;
  423. }
  424. void FireGameEvent_Internal( IGameEvent *event )
  425. {
  426. if ( Q_strcmp( event->GetName(), "player_damaged" ) == 0 )
  427. {
  428. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  429. m_iDamageTotal += event->GetInt( "amount" );
  430. if ( pLocalPlayer && pLocalPlayer->IsAlive() && m_iDamageTotal >= 500 )
  431. {
  432. IncrementCount();
  433. }
  434. }
  435. else if ( FStrEq( event->GetName(), "teamplay_round_active" ) )
  436. {
  437. m_iDamageTotal = 0;
  438. }
  439. else if ( FStrEq( event->GetName(), "localplayer_respawn" ) )
  440. {
  441. m_iDamageTotal = 0;
  442. }
  443. }
  444. private:
  445. int m_iDamageTotal;
  446. };
  447. DECLARE_ACHIEVEMENT( CAchievementTFScout_SurviveDamage, ACHIEVEMENT_TF_SCOUT_SURVIVE_DAMAGE, "TF_SCOUT_SURVIVE_DAMAGE", 5 );
  448. //----------------------------------------------------------------------------------------------------------------
  449. class CAchievementTFScout_ThreeFlagCaptures : public CBaseTFAchievement
  450. {
  451. void Init()
  452. {
  453. SetFlags( ACH_SAVE_GLOBAL );
  454. SetGoal( 1 );
  455. }
  456. virtual void ListenForEvents()
  457. {
  458. ListenForGameEvent( "teamplay_flag_event" );
  459. ListenForGameEvent( "teamplay_round_active" );
  460. m_iFlagCaps = 0;
  461. }
  462. void FireGameEvent_Internal( IGameEvent *event )
  463. {
  464. if ( Q_strcmp( event->GetName(), "teamplay_flag_event" ) == 0 && event->GetInt( "eventtype" ) == TF_FLAGEVENT_CAPTURE )
  465. {
  466. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  467. if ( pLocalPlayer && pLocalPlayer->entindex() == event->GetInt( "player" ))
  468. {
  469. m_iFlagCaps++;
  470. if ( m_iFlagCaps >= 3 )
  471. {
  472. IncrementCount();
  473. }
  474. }
  475. }
  476. else if ( FStrEq( event->GetName(), "teamplay_round_active" ) )
  477. {
  478. m_iFlagCaps = 0;
  479. }
  480. }
  481. private:
  482. int m_iFlagCaps;
  483. };
  484. DECLARE_ACHIEVEMENT( CAchievementTFScout_ThreeFlagCaptures, ACHIEVEMENT_TF_SCOUT_THREE_FLAGCAPS, "TF_SCOUT_THREE_FLAGCAPS", 5 );
  485. //----------------------------------------------------------------------------------------------------------------
  486. class CAchievementTFScout_DoubleJumpKill : public CBaseTFAchievement
  487. {
  488. void Init()
  489. {
  490. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  491. SetGoal( 20 );
  492. SetStoreProgressInSteam( true );
  493. }
  494. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  495. {
  496. C_TFPlayer *pKiller = ToTFPlayer( pAttacker );
  497. int iDoubleJumpKill = pKiller->m_Shared.GetAirDash();
  498. if ( iDoubleJumpKill > 0 )
  499. {
  500. IncrementCount();
  501. }
  502. }
  503. };
  504. DECLARE_ACHIEVEMENT( CAchievementTFScout_DoubleJumpKill, ACHIEVEMENT_TF_SCOUT_DOUBLEJUMP_KILL, "TF_SCOUT_DOUBLEJUMP_KILL", 5 );
  505. //----------------------------------------------------------------------------------------------------------------
  506. class CAchievementTFScout_FlagCapGrind : public CBaseTFAchievement
  507. {
  508. void Init()
  509. {
  510. SetFlags( ACH_SAVE_GLOBAL );
  511. SetGoal( 25 );
  512. SetStoreProgressInSteam( true );
  513. }
  514. virtual void ListenForEvents()
  515. {
  516. ListenForGameEvent( "teamplay_flag_event" );
  517. }
  518. void FireGameEvent_Internal( IGameEvent *event )
  519. {
  520. if ( Q_strcmp( event->GetName(), "teamplay_flag_event" ) == 0 && event->GetInt( "eventtype" ) == TF_FLAGEVENT_CAPTURE )
  521. {
  522. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  523. if ( pLocalPlayer && pLocalPlayer->entindex() == event->GetInt( "player" ))
  524. {
  525. IncrementCount();
  526. }
  527. }
  528. }
  529. };
  530. DECLARE_ACHIEVEMENT( CAchievementTFScout_FlagCapGrind, ACHIEVEMENT_TF_SCOUT_FLAG_CAP_GRIND, "TF_SCOUT_FLAG_CAP_GRIND", 5 );
  531. //----------------------------------------------------------------------------------------------------------------
  532. class CAchievementTFScout_DodgeDamage : public CBaseTFAchievement
  533. {
  534. void Init()
  535. {
  536. SetFlags( ACH_SAVE_GLOBAL );
  537. SetGoal( 1 );
  538. m_iDamageDodged = 0;
  539. }
  540. virtual void ListenForEvents()
  541. {
  542. ListenForGameEvent( "player_damage_dodged" );
  543. ListenForGameEvent( "localplayer_respawn" );
  544. ListenForGameEvent( "teamplay_round_active" );
  545. }
  546. void FireGameEvent_Internal( IGameEvent *event )
  547. {
  548. const char *pszEventName = event->GetName();
  549. if ( FStrEq( pszEventName, "localplayer_respawn" ) ||
  550. FStrEq( pszEventName, "teamplay_round_active" ) )
  551. {
  552. // If we died or respawned, reset...
  553. m_iDamageDodged = 0;
  554. return;
  555. }
  556. else if ( Q_strcmp( event->GetName(), "player_damage_dodged" ) == 0 )
  557. {
  558. m_iDamageDodged += event->GetInt( "damage" );
  559. if ( m_iDamageDodged > 1000 )
  560. {
  561. IncrementCount();
  562. }
  563. }
  564. }
  565. private:
  566. int m_iDamageDodged;
  567. };
  568. DECLARE_ACHIEVEMENT( CAchievementTFScout_DodgeDamage, ACHIEVEMENT_TF_SCOUT_DODGE_DAMAGE, "TF_SCOUT_DODGE_DAMAGE", 5 );
  569. //----------------------------------------------------------------------------------------------------------------
  570. class CAchievementTFScout_KnockIntoTrain : public CBaseTFAchievement
  571. {
  572. void Init()
  573. {
  574. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_KILL_ENEMY_EVENTS );
  575. SetGoal( 1 );
  576. }
  577. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  578. {
  579. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  580. if ( !pTFVictim )
  581. return;
  582. CTFPlayer *pLocalPlayer = ToTFPlayer( CBasePlayer::GetLocalPlayer() );
  583. if ( !pLocalPlayer )
  584. return;
  585. if ( pTFVictim->m_Shared.GetWeaponKnockbackID() == pLocalPlayer->GetUserID() )
  586. {
  587. int custom = event->GetInt( "customkill" );
  588. int damagebits = event->GetInt( "damagebits" );
  589. if ( ( damagebits & DMG_VEHICLE ) || // They were hit by a freakin' train!
  590. ( pAttacker && pAttacker->IsBrushModel() ) || // They were smashed by the world! Gah!
  591. ( !pAttacker || (pAttacker == pVictim) ) || // He killed himself!
  592. ( custom == TF_DMG_CUSTOM_SUICIDE ) ||
  593. ( custom == TF_DMG_CUSTOM_TRIGGER_HURT ) ) // A trigger-hurt got him!
  594. {
  595. IncrementCount();
  596. }
  597. }
  598. }
  599. };
  600. DECLARE_ACHIEVEMENT( CAchievementTFScout_KnockIntoTrain, ACHIEVEMENT_TF_SCOUT_KNOCK_INTO_TRAIN, "TF_SCOUT_KNOCK_INTO_TRAIN", 5 );
  601. //----------------------------------------------------------------------------------------------------------------
  602. class CAchievementTFScout_KillStunned : public CBaseTFAchievement
  603. {
  604. void Init()
  605. {
  606. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_KILL_EVENTS );
  607. SetGoal( 50 );
  608. SetStoreProgressInSteam( true );
  609. }
  610. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  611. {
  612. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  613. if ( !pTFVictim )
  614. return;
  615. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  616. if ( !pLocalPlayer )
  617. return;
  618. if ( pAttacker != pLocalPlayer )
  619. {
  620. int iAssisterIndex = engine->GetPlayerForUserID( event->GetInt( "assister" ) );
  621. if ( iAssisterIndex <= 0 )
  622. return;
  623. CTFPlayer *pAssister = ToTFPlayer( UTIL_PlayerByIndex( iAssisterIndex ) );
  624. if ( pAssister != pLocalPlayer )
  625. return;
  626. }
  627. int iStunFlags = event->GetInt( "stun_flags" );
  628. if ( ((iStunFlags & TF_STUN_CONTROLS) != 0) || ((iStunFlags & TF_STUN_LOSER_STATE) != 0) )
  629. {
  630. IncrementCount();
  631. }
  632. }
  633. };
  634. DECLARE_ACHIEVEMENT( CAchievementTFScout_KillStunned, ACHIEVEMENT_TF_SCOUT_KILL_STUNNED, "TF_SCOUT_KILL_STUNNED", 5 );
  635. //----------------------------------------------------------------------------------------------------------------
  636. class CAchievementTFScout_StunIntoTrain : public CBaseTFAchievement
  637. {
  638. void Init()
  639. {
  640. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_KILL_ENEMY_EVENTS );
  641. SetGoal( 1 );
  642. }
  643. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  644. {
  645. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  646. if ( !pTFVictim )
  647. return;
  648. // Achievement for causing someone we stunned to die by the environment.
  649. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  650. if ( !pLocalPlayer )
  651. return;
  652. int iStunFlags = event->GetInt( "stun_flags" );
  653. bool bLegalStun = ((iStunFlags & TF_STUN_CONTROLS) != 0) || ((iStunFlags & TF_STUN_LOSER_STATE) != 0);
  654. if ( bLegalStun && (pTFVictim->m_Shared.GetStunner() == pLocalPlayer) )
  655. {
  656. int custom = event->GetInt( "customkill" );
  657. int damagebits = event->GetInt( "damagebits" );
  658. if ( ( damagebits & DMG_VEHICLE ) || // They were hit by a freakin' train!
  659. ( pAttacker && pAttacker->IsBrushModel() ) || // They were smashed by the world! Gah!
  660. ( !pAttacker || (pAttacker == pVictim) ) || // He killed himself!
  661. ( custom == TF_DMG_CUSTOM_SUICIDE ) ||
  662. ( custom == TF_DMG_CUSTOM_TRIGGER_HURT ) ) // A trigger-hurt got him!
  663. {
  664. IncrementCount();
  665. }
  666. }
  667. }
  668. };
  669. DECLARE_ACHIEVEMENT( CAchievementTFScout_StunIntoTrain, ACHIEVEMENT_TF_SCOUT_STUN_INTO_TRAIN, "TF_SCOUT_STUN_INTO_TRAIN", 5 );
  670. //----------------------------------------------------------------------------------------------------------------
  671. class CAchievementTFScout_StunUberEnemies : public CBaseTFAchievement
  672. {
  673. void Init()
  674. {
  675. SetFlags( ACH_SAVE_GLOBAL );
  676. SetGoal( 2 );
  677. SetStoreProgressInSteam( true );
  678. }
  679. virtual void ListenForEvents( void )
  680. {
  681. ListenForGameEvent( "player_stunned" );
  682. }
  683. void FireGameEvent_Internal( IGameEvent *event )
  684. {
  685. const char *pszEventName = event->GetName();
  686. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  687. if ( !pLocalPlayer )
  688. return;
  689. if ( FStrEq( pszEventName, "player_stunned" ) )
  690. {
  691. CTFPlayer *pStunner = ToTFPlayer( UTIL_PlayerByIndex( engine->GetPlayerForUserID( event->GetInt( "stunner" ) ) ) );
  692. CTFPlayer *pVictim = ToTFPlayer( UTIL_PlayerByIndex( engine->GetPlayerForUserID( event->GetInt( "victim" ) ) ) );
  693. if ( pStunner == pLocalPlayer )
  694. {
  695. if ( pVictim && pVictim->IsPlayerClass( TF_CLASS_MEDIC ) && pVictim->MedicGetChargeLevel() >= 1.0 )
  696. {
  697. IncrementCount();
  698. }
  699. }
  700. }
  701. }
  702. };
  703. DECLARE_ACHIEVEMENT( CAchievementTFScout_StunUberEnemies, ACHIEVEMENT_TF_SCOUT_STUN_UBER_ENEMIES, "TF_SCOUT_STUN_UBER_ENEMIES", 5 );
  704. //----------------------------------------------------------------------------------------------------------------
  705. class CAchievementTFScout_StunCappingEnemies : public CBaseTFAchievement
  706. {
  707. void Init()
  708. {
  709. SetFlags( ACH_SAVE_GLOBAL );
  710. SetGoal( 50 );
  711. SetStoreProgressInSteam( true );
  712. }
  713. virtual void ListenForEvents( void )
  714. {
  715. ListenForGameEvent( "player_stunned" );
  716. }
  717. void FireGameEvent_Internal( IGameEvent *event )
  718. {
  719. const char *pszEventName = event->GetName();
  720. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  721. if ( !pLocalPlayer )
  722. return;
  723. if ( FStrEq( pszEventName, "player_stunned" ) )
  724. {
  725. CTFPlayer *pStunner = ToTFPlayer( UTIL_PlayerByIndex( engine->GetPlayerForUserID( event->GetInt( "stunner" ) ) ) );
  726. CTFPlayer *pVictim = ToTFPlayer( UTIL_PlayerByIndex( engine->GetPlayerForUserID( event->GetInt( "victim" ) ) ) );
  727. if ( (pStunner == pLocalPlayer) &&
  728. pVictim && event->GetBool( "victim_capping" ) )
  729. {
  730. IncrementCount();
  731. }
  732. }
  733. }
  734. };
  735. DECLARE_ACHIEVEMENT( CAchievementTFScout_StunCappingEnemies, ACHIEVEMENT_TF_SCOUT_STUN_CAPPING_ENEMIES, "TF_SCOUT_STUN_CAPPING_ENEMIES", 5 );
  736. //----------------------------------------------------------------------------------------------------------------
  737. class CAchievementTFScout_MaxStuns : public CBaseTFAchievement
  738. {
  739. void Init()
  740. {
  741. SetFlags( ACH_SAVE_GLOBAL );
  742. SetGoal( 1 );
  743. }
  744. virtual void ListenForEvents( void )
  745. {
  746. ListenForGameEvent( "player_stunned" );
  747. }
  748. void FireGameEvent_Internal( IGameEvent *event )
  749. {
  750. const char *pszEventName = event->GetName();
  751. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  752. if ( !pLocalPlayer )
  753. return;
  754. if ( FStrEq( pszEventName, "player_stunned" ) )
  755. {
  756. CTFPlayer *pStunner = ToTFPlayer( UTIL_PlayerByIndex( engine->GetPlayerForUserID( event->GetInt( "stunner" ) ) ) );
  757. CTFPlayer *pVictim = ToTFPlayer( UTIL_PlayerByIndex( engine->GetPlayerForUserID( event->GetInt( "victim" ) ) ) );
  758. if ( (pStunner == pLocalPlayer) &&
  759. pVictim && event->GetBool( "big_stun" ) )
  760. {
  761. IncrementCount();
  762. }
  763. }
  764. }
  765. };
  766. DECLARE_ACHIEVEMENT( CAchievementTFScout_MaxStuns, ACHIEVEMENT_TF_SCOUT_MAX_STUNS, "TF_SCOUT_MAX_STUNS", 5 );
  767. //----------------------------------------------------------------------------------------------------------------
  768. class CAchievementTFScout_StunScoutWithTheirBall : public CBaseTFAchievement
  769. {
  770. void Init()
  771. {
  772. SetFlags( ACH_SAVE_GLOBAL );
  773. SetGoal( 1 );
  774. }
  775. // server awards this achievement, no other code within achievement necessary
  776. };
  777. DECLARE_ACHIEVEMENT( CAchievementTFScout_StunScoutWithTheirBall, ACHIEVEMENT_TF_SCOUT_STUN_SCOUT_WITH_THEIR_BALL, "TF_SCOUT_STUN_SCOUT_WITH_THEIR_BALL", 5 );
  778. //----------------------------------------------------------------------------------------------------------------
  779. class CAchievementTFScout_KillInDodgeCooldown : public CBaseTFAchievement
  780. {
  781. void Init()
  782. {
  783. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  784. SetGoal( 1 );
  785. SetStoreProgressInSteam( true );
  786. }
  787. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  788. {
  789. // Achievement for killing another scout under the effect Crit-a-Cola
  790. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  791. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SCOUT ) && pTFVictim->m_Shared.InCond( TF_COND_ENERGY_BUFF ) )
  792. {
  793. IncrementCount();
  794. }
  795. }
  796. };
  797. DECLARE_ACHIEVEMENT( CAchievementTFScout_KillInDodgeCooldown, ACHIEVEMENT_TF_SCOUT_KILL_IN_DODGE_COOLDOWN, "TF_SCOUT_KILL_IN_DODGE_COOLDOWN", 5 );
  798. //----------------------------------------------------------------------------------------------------------------
  799. class CAchievementTFScout_KillFromBehind : public CBaseTFAchievement
  800. {
  801. void Init()
  802. {
  803. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  804. SetGoal( 50 );
  805. SetStoreProgressInSteam( true );
  806. }
  807. // Shamelessly stolen from the knife!
  808. float DotProductToTarget( CBaseEntity *pAttacker, CBaseEntity *pTarget )
  809. {
  810. Assert( pTarget );
  811. // Get the forward view vector of the target, ignore Z
  812. Vector vecVictimForward;
  813. AngleVectors( pTarget->EyeAngles(), &vecVictimForward, NULL, NULL );
  814. vecVictimForward.z = 0.0f;
  815. vecVictimForward.NormalizeInPlace();
  816. // Get a vector from my origin to my targets origin
  817. Vector vecToTarget;
  818. vecToTarget = pTarget->WorldSpaceCenter() - pAttacker->WorldSpaceCenter();
  819. vecToTarget.z = 0.0f;
  820. vecToTarget.NormalizeInPlace();
  821. return DotProduct( vecVictimForward, vecToTarget );
  822. }
  823. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  824. {
  825. // Achievement for killing a bunch of enemies from behind with the scattergun double.
  826. if ( event->GetInt( "weaponid" ) == TF_WEAPON_SCATTERGUN )
  827. {
  828. CTFScatterGun *pScattergun = (CTFScatterGun *)ToTFPlayer( C_TFPlayer::GetLocalPlayer() )->Weapon_OwnsThisID( TF_WEAPON_SCATTERGUN );
  829. if ( pScattergun && pScattergun->HasKnockback() &&
  830. ( DotProductToTarget( pAttacker, pVictim ) > -0.1 ) )
  831. {
  832. IncrementCount();
  833. }
  834. }
  835. }
  836. };
  837. DECLARE_ACHIEVEMENT( CAchievementTFScout_KillFromBehind, ACHIEVEMENT_TF_SCOUT_KILL_FROM_BEHIND, "TF_SCOUT_KILL_FROM_BEHIND", 5 );
  838. //----------------------------------------------------------------------------------------------------------------
  839. class CAchievementTFScout_CaptureLastPoint : public CBaseTFAchievement
  840. {
  841. void Init()
  842. {
  843. SetFlags( ACH_SAVE_GLOBAL );
  844. SetGoal( 1 );
  845. m_bRecentCapper = false;
  846. }
  847. virtual void ListenForEvents( void )
  848. {
  849. ListenForGameEvent( "teamplay_point_captured" );
  850. ListenForGameEvent( "teamplay_round_win" );
  851. }
  852. void FireGameEvent_Internal( IGameEvent *event )
  853. {
  854. const char *pszEventName = event->GetName();
  855. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  856. if ( !pLocalPlayer )
  857. return;
  858. if ( FStrEq( pszEventName, "teamplay_point_captured" ) )
  859. {
  860. m_bRecentCapper = false;
  861. int iTeam = event->GetInt( "team" );
  862. if ( iTeam == pLocalPlayer->GetTeamNumber() )
  863. {
  864. const char *cappers = event->GetString( "cappers" );
  865. for ( int i=0; i<Q_strlen( cappers ); i++ )
  866. {
  867. int iPlayerIndex = (int) cappers[i];
  868. CTFPlayer *pPlayer = ToTFPlayer( UTIL_PlayerByIndex( iPlayerIndex ) );
  869. if ( pPlayer == pLocalPlayer )
  870. {
  871. m_bRecentCapper = true;
  872. }
  873. }
  874. }
  875. }
  876. else if ( FStrEq( pszEventName, "teamplay_round_win" ) )
  877. {
  878. // If we're the winners and we were involved in capping the last point, we get this achievement.
  879. int iTeam = event->GetInt( "team" );
  880. if ( (iTeam == pLocalPlayer->GetTeamNumber()) &&
  881. m_bRecentCapper &&
  882. (TFGameRules()->GetGameType() == TF_GAMETYPE_CP) )
  883. {
  884. IncrementCount();
  885. }
  886. m_bRecentCapper = false;
  887. }
  888. }
  889. bool m_bRecentCapper;
  890. };
  891. DECLARE_ACHIEVEMENT( CAchievementTFScout_CaptureLastPoint, ACHIEVEMENT_TF_SCOUT_CAPTURE_LAST_POINT, "TF_SCOUT_CAPTURE_LAST_POINT", 5 );
  892. //----------------------------------------------------------------------------------------------------------------
  893. class CAchievementTFScout_CaptureThreePoints : public CBaseTFAchievement
  894. {
  895. void Init()
  896. {
  897. SetFlags( ACH_SAVE_GLOBAL );
  898. SetGoal( 1 );
  899. m_iPointsCapped = 0;
  900. }
  901. virtual void ListenForEvents( void )
  902. {
  903. ListenForGameEvent( "teamplay_point_captured" );
  904. ListenForGameEvent( "localplayer_respawn" );
  905. ListenForGameEvent( "teamplay_round_active" );
  906. }
  907. void FireGameEvent_Internal( IGameEvent *event )
  908. {
  909. // only on maps with capture points
  910. if ( TFGameRules() && TFGameRules()->GetGameType() != TF_GAMETYPE_CP && TFGameRules()->GetGameType() != TF_GAMETYPE_ARENA )
  911. return;
  912. const char *pszEventName = event->GetName();
  913. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  914. if ( !pLocalPlayer )
  915. return;
  916. if ( FStrEq( pszEventName, "localplayer_respawn" ) ||
  917. FStrEq( pszEventName, "teamplay_round_active") )
  918. {
  919. m_iPointsCapped = 0;
  920. }
  921. else if ( FStrEq( pszEventName, "teamplay_point_captured" ) )
  922. {
  923. int iTeam = event->GetInt( "team" );
  924. if ( iTeam == pLocalPlayer->GetTeamNumber() )
  925. {
  926. const char *cappers = event->GetString( "cappers" );
  927. for ( int i=0; i<Q_strlen( cappers ); i++ )
  928. {
  929. int iPlayerIndex = (int) cappers[i];
  930. CTFPlayer *pPlayer = ToTFPlayer( UTIL_PlayerByIndex( iPlayerIndex ) );
  931. if ( pPlayer == pLocalPlayer )
  932. {
  933. m_iPointsCapped++;
  934. }
  935. }
  936. }
  937. if ( m_iPointsCapped == 3 )
  938. {
  939. IncrementCount();
  940. }
  941. }
  942. }
  943. int m_iPointsCapped;
  944. };
  945. DECLARE_ACHIEVEMENT( CAchievementTFScout_CaptureThreePoints, ACHIEVEMENT_TF_SCOUT_CAPTURE_THREE_POINTS, "TF_SCOUT_CAPTURE_THREE_POINTS", 5 );
  946. //----------------------------------------------------------------------------------------------------------------
  947. class CAchievementTFScout_FastCap : public CBaseTFAchievement
  948. {
  949. void Init()
  950. {
  951. SetFlags( ACH_SAVE_GLOBAL );
  952. SetGoal( 1 );
  953. }
  954. virtual void ListenForEvents( void )
  955. {
  956. ListenForGameEvent( "teamplay_point_startcapture" );
  957. }
  958. void FireGameEvent_Internal( IGameEvent *event )
  959. {
  960. // only on maps with capture points
  961. if ( TFGameRules() && TFGameRules()->GetGameType() != TF_GAMETYPE_CP && TFGameRules()->GetGameType() != TF_GAMETYPE_ARENA )
  962. return;
  963. const char *pszEventName = event->GetName();
  964. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  965. if ( !pLocalPlayer )
  966. return;
  967. if ( FStrEq( pszEventName, "teamplay_point_startcapture" ) )
  968. {
  969. const char *cappers = event->GetString( "cappers" );
  970. for ( int i=0; i<Q_strlen( cappers ); i++ )
  971. {
  972. int iPlayerIndex = (int) cappers[i];
  973. CTFPlayer *pPlayer = ToTFPlayer( UTIL_PlayerByIndex( iPlayerIndex ) );
  974. if ( pPlayer == pLocalPlayer )
  975. {
  976. if ( event->GetFloat( "captime" ) < 1.0 )
  977. {
  978. IncrementCount();
  979. }
  980. }
  981. }
  982. }
  983. }
  984. };
  985. DECLARE_ACHIEVEMENT( CAchievementTFScout_FastCap, ACHIEVEMENT_TF_SCOUT_FAST_CAP, "TF_SCOUT_FAST_CAP", 5 );
  986. //----------------------------------------------------------------------------------------------------------------
  987. class CAchievementTFScout_StartAndFinishCap : public CBaseTFAchievement
  988. {
  989. void Init()
  990. {
  991. SetFlags( ACH_SAVE_GLOBAL );
  992. SetGoal( 10 );
  993. SetStoreProgressInSteam( true );
  994. m_Points.Purge();
  995. }
  996. virtual void ListenForEvents( void )
  997. {
  998. ListenForGameEvent( "teamplay_point_startcapture" );
  999. ListenForGameEvent( "teamplay_point_captured" );
  1000. ListenForGameEvent( "teamplay_capture_broken" );
  1001. ListenForGameEvent( "teamplay_round_active" );
  1002. }
  1003. void FireGameEvent_Internal( IGameEvent *event )
  1004. {
  1005. const char *pszEventName = event->GetName();
  1006. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  1007. if ( !pLocalPlayer )
  1008. return;
  1009. // Achievement for initiating captures that ultimately succeed.
  1010. if ( FStrEq( pszEventName, "teamplay_point_startcapture" ) )
  1011. {
  1012. const char *cappers = event->GetString( "cappers" );
  1013. for ( int i=0; i<Q_strlen( cappers ); i++ )
  1014. {
  1015. int iPlayerIndex = (int) cappers[i];
  1016. CTFPlayer *pPlayer = ToTFPlayer( UTIL_PlayerByIndex( iPlayerIndex ) );
  1017. if ( pPlayer == pLocalPlayer ) // Are we one of the cappers?
  1018. {
  1019. // We started capping this point.
  1020. m_Points.AddToTail( event->GetInt( "cp" ) );
  1021. }
  1022. }
  1023. }
  1024. else if ( FStrEq( pszEventName, "teamplay_point_captured" ) )
  1025. {
  1026. int iIndex = m_Points.Find( event->GetInt( "cp" ) );
  1027. if ( iIndex > -1 ) // Is the point one we started capping?
  1028. {
  1029. int iTeam = event->GetInt( "team" );
  1030. if ( iTeam == pLocalPlayer->GetTeamNumber() )
  1031. {
  1032. m_Points.Remove( iIndex );
  1033. IncrementCount();
  1034. }
  1035. }
  1036. }
  1037. else if ( FStrEq( pszEventName, "teamplay_capture_broken" ) )
  1038. {
  1039. // Our team failed to complete the capture.
  1040. int iIndex = m_Points.Find( event->GetInt( "cp" ) );
  1041. if ( iIndex > -1 )
  1042. {
  1043. m_Points.Remove( iIndex );
  1044. }
  1045. }
  1046. else if ( FStrEq( pszEventName, "teamplay_round_active" ) )
  1047. {
  1048. // Reset tracking at the start of a new round.
  1049. m_Points.Purge();
  1050. }
  1051. }
  1052. CUtlVector< int > m_Points;
  1053. };
  1054. DECLARE_ACHIEVEMENT( CAchievementTFScout_StartAndFinishCap, ACHIEVEMENT_TF_SCOUT_START_AND_FINISH_CAP, "TF_SCOUT_START_AND_FINISH_CAP", 5 );
  1055. //----------------------------------------------------------------------------------------------------------------
  1056. class CAchievementTFScout_BlockCaps : public CBaseTFAchievement
  1057. {
  1058. void Init()
  1059. {
  1060. SetFlags( ACH_SAVE_GLOBAL );
  1061. SetGoal( 50 );
  1062. SetStoreProgressInSteam( true );
  1063. }
  1064. virtual void ListenForEvents( void )
  1065. {
  1066. ListenForGameEvent( "teamplay_capture_blocked" );
  1067. }
  1068. void FireGameEvent_Internal( IGameEvent *event )
  1069. {
  1070. const char *pszEventName = event->GetName();
  1071. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  1072. if ( !pLocalPlayer )
  1073. return;
  1074. // Achievement for blocking captures!
  1075. if ( FStrEq( pszEventName, "teamplay_capture_blocked" ) )
  1076. {
  1077. int iBlocker = event->GetInt( "blocker" );
  1078. if ( (iBlocker == pLocalPlayer->entindex()) &&
  1079. ((TFGameRules()->GetGameType() == TF_GAMETYPE_CP) ||
  1080. (TFGameRules()->GetGameType() == TF_GAMETYPE_ARENA)) )
  1081. {
  1082. IncrementCount();
  1083. }
  1084. }
  1085. }
  1086. };
  1087. DECLARE_ACHIEVEMENT( CAchievementTFScout_BlockCaps, ACHIEVEMENT_TF_SCOUT_BLOCK_CAPS, "TF_SCOUT_BLOCK_CAPS", 5 );
  1088. //----------------------------------------------------------------------------------------------------------------
  1089. class CAchievementTFScout_CarrierKillCarrier : public CBaseTFAchievement
  1090. {
  1091. void Init()
  1092. {
  1093. SetFlags( ACH_SAVE_GLOBAL );
  1094. SetGoal( 1 );
  1095. }
  1096. virtual void ListenForEvents( void )
  1097. {
  1098. ListenForGameEvent( "teamplay_flag_event" );
  1099. }
  1100. void FireGameEvent_Internal( IGameEvent *event )
  1101. {
  1102. const char *pszEventName = event->GetName();
  1103. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  1104. if ( !pLocalPlayer )
  1105. return;
  1106. // Achievement for blocking captures!
  1107. if ( FStrEq( pszEventName, "teamplay_flag_event" ) )
  1108. {
  1109. int iType = event->GetInt( "eventtype" );
  1110. if ( iType == TF_FLAGEVENT_DEFEND )
  1111. {
  1112. int iPlayer = event->GetInt( "player" );
  1113. if ( (iPlayer == pLocalPlayer->entindex()) && pLocalPlayer->HasTheFlag() )
  1114. {
  1115. IncrementCount();
  1116. }
  1117. }
  1118. }
  1119. }
  1120. };
  1121. DECLARE_ACHIEVEMENT( CAchievementTFScout_CarrierKillCarrier, ACHIEVEMENT_TF_SCOUT_CARRIER_KILL_CARRIER, "TF_SCOUT_CARRIER_KILL_CARRIER", 5 );
  1122. //----------------------------------------------------------------------------------------------------------------
  1123. class CAchievementTFScout_CapFlagWithoutAttacking : public CBaseTFAchievement
  1124. {
  1125. void Init()
  1126. {
  1127. SetFlags( ACH_SAVE_GLOBAL );
  1128. SetGoal( 1 );
  1129. }
  1130. virtual void ListenForEvents( void )
  1131. {
  1132. ListenForGameEvent( "teamplay_flag_event" );
  1133. }
  1134. void FireGameEvent_Internal( IGameEvent *event )
  1135. {
  1136. const char *pszEventName = event->GetName();
  1137. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  1138. if ( !pLocalPlayer )
  1139. return;
  1140. // Achievement for capping the flag without shooting anyone.
  1141. if ( FStrEq( pszEventName, "teamplay_flag_event" ) )
  1142. {
  1143. int iType = event->GetInt( "eventtype" );
  1144. if ( iType == TF_FLAGEVENT_CAPTURE )
  1145. {
  1146. int iPlayer = event->GetInt( "player" );
  1147. if ( (iPlayer == pLocalPlayer->entindex()) && !pLocalPlayer->HasFiredWeapon() )
  1148. {
  1149. IncrementCount();
  1150. }
  1151. }
  1152. else if ( iType == TF_FLAGEVENT_PICKUP )
  1153. {
  1154. int iPlayer = event->GetInt( "player" );
  1155. if ( iPlayer == pLocalPlayer->entindex() )
  1156. {
  1157. pLocalPlayer->SetFiredWeapon( false );
  1158. }
  1159. }
  1160. }
  1161. }
  1162. };
  1163. DECLARE_ACHIEVEMENT( CAchievementTFScout_CapFlagWithoutAttacking, ACHIEVEMENT_TF_SCOUT_CAP_FLAG_WITHOUT_ATTACKING, "TF_SCOUT_CAP_FLAG_WITHOUT_ATTACKING", 5 );
  1164. //----------------------------------------------------------------------------------------------------------------
  1165. class CAchievementTFScout_LongDistanceRunner : public CBaseTFAchievement
  1166. {
  1167. void Init()
  1168. {
  1169. SetFlags( ACH_SAVE_GLOBAL );
  1170. SetGoal( 25000 );
  1171. SetStoreProgressInSteam( true );
  1172. }
  1173. virtual void ListenForEvents( void )
  1174. {
  1175. ListenForGameEvent( "player_death" );
  1176. }
  1177. void FireGameEvent_Internal( IGameEvent *event )
  1178. {
  1179. const char *pszEventName = event->GetName();
  1180. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  1181. if ( !pLocalPlayer )
  1182. return;
  1183. // Achievement for running ...
  1184. bool bUpdate = false;
  1185. if ( FStrEq( pszEventName, "player_death" ) )
  1186. {
  1187. int iVictimID = event->GetInt( "userid" );
  1188. if ( pLocalPlayer && (iVictimID == pLocalPlayer->GetUserID()) )
  1189. {
  1190. bUpdate = true;
  1191. }
  1192. }
  1193. else if ( FStrEq( pszEventName, "teamplay_round_win" ) )
  1194. {
  1195. bUpdate = true;
  1196. }
  1197. if ( bUpdate )
  1198. {
  1199. float fMeters = pLocalPlayer->GetMetersRan();
  1200. IncrementCount( ceil( fMeters ) );
  1201. }
  1202. }
  1203. };
  1204. DECLARE_ACHIEVEMENT( CAchievementTFScout_LongDistanceRunner, ACHIEVEMENT_TF_SCOUT_LONG_DISTANCE_RUNNER, "TF_SCOUT_LONG_DISTANCE_RUNNER", 5 );
  1205. //----------------------------------------------------------------------------------------------------------------
  1206. class CAchievementTFScout_TauntKill : public CBaseTFAchievement
  1207. {
  1208. void Init()
  1209. {
  1210. SetFlags( ACH_SAVE_GLOBAL );
  1211. SetGoal( 1 );
  1212. m_iTargetID = 0;
  1213. m_vSlamOrigin = Vector(0,0,0);
  1214. }
  1215. virtual void ListenForEvents( void )
  1216. {
  1217. ListenForGameEvent( "scout_grand_slam" );
  1218. ListenForGameEvent( "scout_slamdoll_landed" );
  1219. ListenForGameEvent( "localplayer_respawn" );
  1220. ListenForGameEvent( "teamplay_round_active" );
  1221. }
  1222. void FireGameEvent_Internal( IGameEvent *event )
  1223. {
  1224. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  1225. if ( !pLocalPlayer )
  1226. return;
  1227. const char *pszEventName = event->GetName();
  1228. if ( FStrEq( pszEventName, "localplayer_respawn" ) ||
  1229. FStrEq( pszEventName, "teamplay_round_active" ) )
  1230. {
  1231. // If we died or respawned, reset...
  1232. m_iTargetID = 0;
  1233. m_vSlamOrigin = Vector(0,0,0);
  1234. return;
  1235. }
  1236. else if ( FStrEq( pszEventName, "scout_grand_slam" ) )
  1237. {
  1238. int iScoutID = event->GetInt( "scout_id" );
  1239. if ( pLocalPlayer && (iScoutID == pLocalPlayer->GetUserID()) )
  1240. {
  1241. m_iTargetID = event->GetInt( "target_id" ); // target_id is a userid
  1242. int iTarget = engine->GetPlayerForUserID( m_iTargetID );
  1243. CBaseEntity *pTarget = UTIL_PlayerByIndex( iTarget );
  1244. if ( pTarget )
  1245. {
  1246. m_vSlamOrigin = pTarget->GetAbsOrigin();
  1247. }
  1248. }
  1249. }
  1250. else if ( FStrEq( pszEventName, "scout_slamdoll_landed" ) )
  1251. {
  1252. int iTargetIndex = event->GetInt( "target_index" ); // target_index is an entindex
  1253. EHANDLE hPlayer = cl_entitylist->GetNetworkableHandle( iTargetIndex );
  1254. if ( !hPlayer )
  1255. return;
  1256. C_TFPlayer *pPlayer = dynamic_cast< C_TFPlayer* >( hPlayer.Get() );
  1257. if ( pPlayer && (m_iTargetID == pPlayer->GetUserID()) &&
  1258. (m_vSlamOrigin != Vector(0,0,0)) )
  1259. {
  1260. float x = event->GetFloat( "x" );
  1261. float y = event->GetFloat( "y" );
  1262. float z = event->GetFloat( "z" );
  1263. Vector vHitOrigin = Vector(x,y,z);
  1264. float fDist = (vHitOrigin - m_vSlamOrigin).Length();
  1265. if ( fDist > 1000 )
  1266. {
  1267. IncrementCount();
  1268. }
  1269. }
  1270. }
  1271. }
  1272. int m_iTargetID;
  1273. Vector m_vSlamOrigin;
  1274. };
  1275. DECLARE_ACHIEVEMENT( CAchievementTFScout_TauntKill, ACHIEVEMENT_TF_SCOUT_TAUNT_KILL, "TF_SCOUT_TAUNT_KILL", 5 );
  1276. //----------------------------------------------------------------------------------------------------------------
  1277. class CAchievementTFScout_AchieveProgress1 : public CAchievement_AchievedCount
  1278. {
  1279. public:
  1280. DECLARE_CLASS( CAchievementTFScout_AchieveProgress1, CAchievement_AchievedCount );
  1281. void Init()
  1282. {
  1283. BaseClass::Init();
  1284. SetAchievementsRequired( 10, ACHIEVEMENT_TF_SCOUT_START_RANGE, ACHIEVEMENT_TF_SCOUT_END_RANGE );
  1285. }
  1286. };
  1287. DECLARE_ACHIEVEMENT( CAchievementTFScout_AchieveProgress1, ACHIEVEMENT_TF_SCOUT_ACHIEVE_PROGRESS1, "TF_SCOUT_ACHIEVE_PROGRESS1", 5 );
  1288. //----------------------------------------------------------------------------------------------------------------
  1289. class CAchievementTFScout_AchieveProgress2 : public CAchievement_AchievedCount
  1290. {
  1291. public:
  1292. DECLARE_CLASS( CAchievementTFScout_AchieveProgress2, CAchievement_AchievedCount );
  1293. void Init()
  1294. {
  1295. BaseClass::Init();
  1296. SetAchievementsRequired( 16, ACHIEVEMENT_TF_SCOUT_START_RANGE, ACHIEVEMENT_TF_SCOUT_END_RANGE );
  1297. }
  1298. };
  1299. DECLARE_ACHIEVEMENT( CAchievementTFScout_AchieveProgress2, ACHIEVEMENT_TF_SCOUT_ACHIEVE_PROGRESS2, "TF_SCOUT_ACHIEVE_PROGRESS2", 5 );
  1300. //----------------------------------------------------------------------------------------------------------------
  1301. class CAchievementTFScout_AchieveProgress3 : public CAchievement_AchievedCount
  1302. {
  1303. public:
  1304. DECLARE_CLASS( CAchievementTFScout_AchieveProgress3, CAchievement_AchievedCount );
  1305. void Init()
  1306. {
  1307. BaseClass::Init();
  1308. SetAchievementsRequired( 22, ACHIEVEMENT_TF_SCOUT_START_RANGE, ACHIEVEMENT_TF_SCOUT_END_RANGE );
  1309. }
  1310. };
  1311. DECLARE_ACHIEVEMENT( CAchievementTFScout_AchieveProgress3, ACHIEVEMENT_TF_SCOUT_ACHIEVE_PROGRESS3, "TF_SCOUT_ACHIEVE_PROGRESS3", 5 );
  1312. // Receive the DamageDodged user message and send out a clientside event for achievements to hook.
  1313. void __MsgFunc_DamageDodged( bf_read &msg )
  1314. {
  1315. int iDamage = msg.ReadShort();
  1316. IGameEvent *event = gameeventmanager->CreateEvent( "player_damage_dodged" );
  1317. if ( event )
  1318. {
  1319. event->SetInt( "damage", iDamage );
  1320. gameeventmanager->FireEventClientSide( event );
  1321. }
  1322. }
  1323. //----------------------------------------------------------------------------------------------------------------
  1324. class CAchievementTFScout_BackscatterKillSpyGrind : public CBaseTFAchievement
  1325. {
  1326. public:
  1327. void Init()
  1328. {
  1329. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
  1330. SetGoal( 20 );
  1331. SetStoreProgressInSteam( true );
  1332. }
  1333. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1334. {
  1335. if ( pVictim && ( pAttacker == C_TFPlayer::GetLocalTFPlayer() ) )
  1336. {
  1337. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  1338. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SPY ) )
  1339. {
  1340. if ( ( event->GetInt( "weaponid" ) == TF_WEAPON_SCATTERGUN ) && ( event->GetInt( "damagebits" ) & DMG_CRITICAL ) )
  1341. {
  1342. CTFPlayer *pTFAttacker = ToTFPlayer( pAttacker );
  1343. if ( pTFAttacker )
  1344. {
  1345. CTFWeaponBase *pWeapon = pTFAttacker->GetActiveTFWeapon();
  1346. if ( pWeapon )
  1347. {
  1348. int iMiniCritBackAttack = 0;
  1349. CALL_ATTRIB_HOOK_INT_ON_OTHER( pWeapon, iMiniCritBackAttack, closerange_backattack_minicrits );
  1350. if ( iMiniCritBackAttack > 0 )
  1351. {
  1352. IncrementCount();
  1353. }
  1354. }
  1355. }
  1356. }
  1357. }
  1358. }
  1359. }
  1360. };
  1361. DECLARE_ACHIEVEMENT( CAchievementTFScout_BackscatterKillSpyGrind, ACHIEVEMENT_TF_SCOUT_BACKSCATTER_KILL_SPY_GRIND, "TF_SCOUT_BACKSCATTER_KILL_SPY_GRIND", 5 );
  1362. //----------------------------------------------------------------------------------------------------------------
  1363. class CAchievementTFScout_BackscatterKillHeavyMedicPair : public CBaseTFAchievement
  1364. {
  1365. public:
  1366. void Init()
  1367. {
  1368. SetFlags( ACH_LISTEN_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
  1369. SetGoal( 1 );
  1370. }
  1371. virtual void ListenForEvents( void )
  1372. {
  1373. ListenForGameEvent( "localplayer_respawn" );
  1374. ListenForGameEvent( "teamplay_round_active" );
  1375. m_hTargets.Purge();
  1376. }
  1377. void FireGameEvent_Internal( IGameEvent *event )
  1378. {
  1379. const char *pszEventName = event->GetName();
  1380. if ( FStrEq( pszEventName, "localplayer_respawn" ) ||
  1381. FStrEq( pszEventName, "teamplay_round_active" ) )
  1382. {
  1383. m_hTargets.Purge();
  1384. }
  1385. }
  1386. int GetTargetIndex( CBaseEntity *pTarget )
  1387. {
  1388. for ( int i = 0; i < m_hTargets.Count(); i++ )
  1389. {
  1390. if ( m_hTargets[i].hTarget == pTarget )
  1391. return i;
  1392. }
  1393. return -1;
  1394. }
  1395. void AddNewTarget( CBaseEntity *pTarget )
  1396. {
  1397. if ( !pTarget )
  1398. return;
  1399. // see if the target is already in our list or get a new index
  1400. int iTargetIndex = GetTargetIndex( pTarget );
  1401. if ( iTargetIndex == -1 )
  1402. {
  1403. iTargetIndex = m_hTargets.AddToTail();
  1404. }
  1405. m_hTargets[iTargetIndex].hTarget = pTarget;
  1406. m_hTargets[iTargetIndex].flTimeToBeat = gpGlobals->curtime + 20.0f; // 20 seconds to kill the target
  1407. }
  1408. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1409. {
  1410. if ( pVictim && ( pAttacker == C_TFPlayer::GetLocalTFPlayer() ) )
  1411. {
  1412. if ( event->GetInt( "weaponid" ) == TF_WEAPON_SCATTERGUN )
  1413. {
  1414. CTFPlayer *pTFAttacker = ToTFPlayer( pAttacker );
  1415. if ( pTFAttacker )
  1416. {
  1417. CTFWeaponBase *pWeapon = pTFAttacker->GetActiveTFWeapon();
  1418. if ( pWeapon )
  1419. {
  1420. int iMiniCritBackAttack = 0;
  1421. CALL_ATTRIB_HOOK_INT_ON_OTHER( pWeapon, iMiniCritBackAttack, closerange_backattack_minicrits );
  1422. if ( iMiniCritBackAttack > 0 )
  1423. {
  1424. // is this victim in our list of targets?
  1425. int index = GetTargetIndex( pVictim );
  1426. if ( index != -1 )
  1427. {
  1428. // did we beat the time?
  1429. if ( m_hTargets[index].flTimeToBeat > gpGlobals->curtime )
  1430. {
  1431. IncrementCount();
  1432. }
  1433. }
  1434. else
  1435. {
  1436. CTFPlayer *pNewTarget = NULL;
  1437. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  1438. if ( pTFVictim->IsPlayerClass( TF_CLASS_HEAVYWEAPONS ) )
  1439. {
  1440. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  1441. {
  1442. pNewTarget = ToTFPlayer( UTIL_PlayerByIndex( i ) );
  1443. if ( pNewTarget && pNewTarget->IsPlayerClass( TF_CLASS_MEDIC ) && ( pNewTarget->MedicGetHealTarget() == pTFVictim ) )
  1444. {
  1445. // add all of his Medics to our list of targets (could be more than one Medic)
  1446. AddNewTarget( pNewTarget );
  1447. }
  1448. }
  1449. }
  1450. else if ( pTFVictim->IsPlayerClass( TF_CLASS_MEDIC ) )
  1451. {
  1452. pNewTarget = ToTFPlayer( pTFVictim->MedicGetHealTarget() );
  1453. if ( pNewTarget && ( pNewTarget->IsPlayerClass( TF_CLASS_HEAVYWEAPONS ) ) )
  1454. {
  1455. AddNewTarget( pNewTarget );
  1456. }
  1457. }
  1458. }
  1459. }
  1460. }
  1461. }
  1462. }
  1463. }
  1464. // is this victim in our list of targets?
  1465. int index = GetTargetIndex( pVictim );
  1466. if ( index != -1 )
  1467. {
  1468. m_hTargets.Remove( index );
  1469. }
  1470. }
  1471. private:
  1472. struct targets_t
  1473. {
  1474. EHANDLE hTarget;
  1475. float flTimeToBeat;
  1476. };
  1477. CUtlVector<targets_t> m_hTargets;
  1478. };
  1479. DECLARE_ACHIEVEMENT( CAchievementTFScout_BackscatterKillHeavyMedicPair, ACHIEVEMENT_TF_SCOUT_BACKSCATTER_KILL_HEAVY_MEDIC_PAIR, "TF_SCOUT_BACKSCATTER_KILL_HEAVY_MEDIC_PAIR", 5 );
  1480. //----------------------------------------------------------------------------------------------------------------
  1481. class CAchievementTFScout_BackscatterKillFriendsGrind : public CBaseTFAchievement
  1482. {
  1483. public:
  1484. void Init()
  1485. {
  1486. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
  1487. SetGoal( 20 );
  1488. SetStoreProgressInSteam( true );
  1489. }
  1490. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1491. {
  1492. if ( pVictim && ( pAttacker == C_TFPlayer::GetLocalTFPlayer() ) )
  1493. {
  1494. if ( ( event->GetInt( "weaponid" ) == TF_WEAPON_SCATTERGUN ) && ( event->GetInt( "damagebits" ) & DMG_CRITICAL ) )
  1495. {
  1496. CTFPlayer *pTFAttacker = ToTFPlayer( pAttacker );
  1497. if ( pTFAttacker )
  1498. {
  1499. CTFWeaponBase *pWeapon = pTFAttacker->GetActiveTFWeapon();
  1500. if ( pWeapon )
  1501. {
  1502. int iMiniCritBackAttack = 0;
  1503. CALL_ATTRIB_HOOK_INT_ON_OTHER( pWeapon, iMiniCritBackAttack, closerange_backattack_minicrits );
  1504. if ( iMiniCritBackAttack > 0 )
  1505. {
  1506. if ( !steamapicontext->SteamFriends() || !steamapicontext->SteamUtils() || !g_pGameRules->IsMultiplayer() )
  1507. return;
  1508. player_info_t pi;
  1509. if ( !engine->GetPlayerInfo( pVictim->entindex(), &pi ) )
  1510. return;
  1511. if ( !pi.friendsID )
  1512. return;
  1513. // check and see if they're on the local player's friends list
  1514. CSteamID steamID( pi.friendsID, 1, GetUniverse(), k_EAccountTypeIndividual );
  1515. if ( steamapicontext->SteamFriends()->HasFriend( steamID, k_EFriendFlagImmediate ) )
  1516. {
  1517. IncrementCount();
  1518. }
  1519. }
  1520. }
  1521. }
  1522. }
  1523. }
  1524. }
  1525. };
  1526. DECLARE_ACHIEVEMENT( CAchievementTFScout_BackscatterKillFriendsGrind, ACHIEVEMENT_TF_SCOUT_BACKSCATTER_KILL_FRIENDS_GRIND, "TF_SCOUT_BACKSCATTER_KILL_FRIENDS_GRIND", 5 );
  1527. #endif // CLIENT_DLL