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.

1885 lines
55 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_shovel.h"
  18. #include "movevars_shared.h"
  19. //======================================================================================================================================
  20. // DEMOMAN ACHIEVEMENT PACK
  21. //======================================================================================================================================
  22. //----------------------------------------------------------------------------------------------------------------
  23. class CAchievementTFDemoman_KillSoldierGrind : public CBaseTFAchievement
  24. {
  25. void Init()
  26. {
  27. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  28. SetGoal( 500 );
  29. SetStoreProgressInSteam( true );
  30. }
  31. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  32. {
  33. if ( !pVictim || !pVictim->IsPlayer() )
  34. return;
  35. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  36. {
  37. // no friendly fire kills
  38. if ( pVictim->GetTeamNumber() != pAttacker->GetTeamNumber() )
  39. {
  40. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  41. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SOLDIER ) )
  42. {
  43. // we killed a soldier
  44. IncrementCount();
  45. }
  46. }
  47. }
  48. }
  49. };
  50. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillSoldierGrind, ACHIEVEMENT_TF_DEMOMAN_KILL_SOLDIER_GRIND, "TF_DEMOMAN_KILL_SOLDIER_GRIND", 5 );
  51. //----------------------------------------------------------------------------------------------------------------
  52. class CAchievementTFDemoman_DestroyBuildingsWithMedic : public CBaseTFAchievement
  53. {
  54. DECLARE_CLASS( CAchievementTFDemoman_DestroyBuildingsWithMedic, CBaseTFAchievement );
  55. void Init()
  56. {
  57. SetFlags( ACH_SAVE_GLOBAL );
  58. SetGoal( 1 );
  59. m_iBuildingsDestroyed = 0;
  60. }
  61. virtual void ListenForEvents()
  62. {
  63. BaseClass::ListenForEvents();
  64. ListenForGameEvent( "player_invulned" );
  65. ListenForGameEvent( "object_destroyed" );
  66. }
  67. virtual void FireGameEvent_Internal( IGameEvent *event )
  68. {
  69. if ( FStrEq( event->GetName(), "player_invulned" ) )
  70. {
  71. int iTarget = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
  72. CBaseEntity *pPlayer = UTIL_PlayerByIndex( iTarget );
  73. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  74. if ( pPlayer == pLocalPlayer )
  75. {
  76. m_iBuildingsDestroyed = 0;
  77. }
  78. }
  79. else if ( Q_strcmp( event->GetName(), "object_destroyed" ) == 0 )
  80. {
  81. int iAttackerIndex = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
  82. if ( iAttackerIndex > 0 )
  83. {
  84. CBaseEntity *pAttacker = UTIL_PlayerByIndex( iAttackerIndex );
  85. C_TFPlayer *pTFPlayer = C_TFPlayer::GetLocalTFPlayer();
  86. if ( pTFPlayer && pTFPlayer == pAttacker )
  87. {
  88. if ( pTFPlayer->m_Shared.InCond( TF_COND_INVULNERABLE ) || pTFPlayer->m_Shared.InCond( TF_COND_CRITBOOSTED ) ||
  89. pTFPlayer->m_Shared.InCond( TF_COND_INVULNERABLE_WEARINGOFF ) )
  90. {
  91. m_iBuildingsDestroyed++;
  92. if ( m_iBuildingsDestroyed >= 5 )
  93. {
  94. IncrementCount();
  95. }
  96. }
  97. }
  98. }
  99. }
  100. else
  101. {
  102. BaseClass::FireGameEvent_Internal( event );
  103. }
  104. }
  105. private:
  106. int m_iBuildingsDestroyed;
  107. };
  108. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DestroyBuildingsWithMedic, ACHIEVEMENT_TF_DEMOMAN_DESTROY_BUILDINGS_WITH_MEDIC, "TF_DEMOMAN_DESTROY_BUILDINGS_WITH_MEDIC", 5 );
  109. //----------------------------------------------------------------------------------------------------------------
  110. class CAchievementTFDemoman_DecapitateCloakedSpy : public CBaseTFAchievement
  111. {
  112. void Init()
  113. {
  114. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL );
  115. SetGoal( 1 );
  116. }
  117. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  118. {
  119. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  120. if ( !pTFVictim )
  121. return;
  122. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  123. if ( !pLocalPlayer )
  124. return;
  125. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SPY ) && pTFVictim->m_Shared.InCond( TF_COND_STEALTHED ) )
  126. {
  127. int customdmg = event->GetInt( "customkill" );
  128. if ( customdmg == TF_DMG_CUSTOM_DECAPITATION )
  129. {
  130. IncrementCount();
  131. }
  132. }
  133. }
  134. };
  135. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DecapitateCloakedSpy, ACHIEVEMENT_TF_DEMOMAN_DECAPITATE_CLOAKED_SPY, "TF_DEMOMAN_DECAPITATE_CLOAKED_SPY", 5 );
  136. //----------------------------------------------------------------------------------------------------------------
  137. class CAchievementTFDemoman_KillWithDirectPipe : public CBaseTFAchievement
  138. {
  139. void Init()
  140. {
  141. SetFlags( ACH_SAVE_GLOBAL );
  142. SetGoal( 50 );
  143. SetStoreProgressInSteam( true );
  144. }
  145. // Kill 50 enemies with direct hits from the pipebomb launcher
  146. // The server (tf_player) awards this achievement - no code necessary
  147. };
  148. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillWithDirectPipe, ACHIEVEMENT_TF_DEMOMAN_KILL_X_WITH_DIRECTPIPE, "TF_DEMOMAN_KILL_X_WITH_DIRECTPIPE", 5 );
  149. //----------------------------------------------------------------------------------------------------------------
  150. class CAchievementTFDemoman_BounceAndKill : public CBaseTFAchievement
  151. {
  152. void Init()
  153. {
  154. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL );
  155. SetGoal( 1 );
  156. SetDefLessFunc( m_BouncedPlayers );
  157. }
  158. virtual void ListenForEvents()
  159. {
  160. ListenForGameEvent( "teamplay_round_active" );
  161. ListenForGameEvent( "localplayer_respawn" );
  162. ListenForGameEvent( "player_hurt" );
  163. m_BouncedPlayers.RemoveAll();
  164. }
  165. void FireGameEvent_Internal( IGameEvent *event )
  166. {
  167. if ( FStrEq( event->GetName(), "teamplay_round_active" ) ||
  168. FStrEq( event->GetName(), "localplayer_respawn" ) )
  169. {
  170. m_BouncedPlayers.RemoveAll();
  171. }
  172. else if ( FStrEq( event->GetName(), "player_hurt" ) )
  173. {
  174. int iAttacker = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
  175. CBasePlayer *pAttacker = UTIL_PlayerByIndex( iAttacker );
  176. if ( pAttacker == C_TFPlayer::GetLocalTFPlayer() )
  177. {
  178. int iVictim = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
  179. CBasePlayer *pVictim = UTIL_PlayerByIndex( iVictim );
  180. if ( pVictim )
  181. {
  182. bool bVictimGrounded = pVictim->GetFlags() & FL_ONGROUND;
  183. if ( bVictimGrounded )
  184. {
  185. int iIndex = m_BouncedPlayers.Find( pVictim->GetUserID() );
  186. if ( iIndex != m_BouncedPlayers.InvalidIndex() )
  187. {
  188. // they're already in our list
  189. m_BouncedPlayers[iIndex] = gpGlobals->curtime;
  190. }
  191. else
  192. {
  193. // we need to add them
  194. m_BouncedPlayers.Insert( pVictim->GetUserID(), gpGlobals->curtime );
  195. }
  196. }
  197. }
  198. }
  199. }
  200. }
  201. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  202. {
  203. if ( pVictim == C_BasePlayer::GetLocalPlayer() )
  204. {
  205. m_BouncedPlayers.RemoveAll();
  206. return;
  207. }
  208. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  209. {
  210. C_TFPlayer *pTFVictim = ToTFPlayer( pVictim );
  211. if ( pTFVictim && !( pTFVictim->GetFlags() & FL_ONGROUND ) )
  212. {
  213. int iIndex = m_BouncedPlayers.Find( pTFVictim->GetUserID() );
  214. if ( iIndex != m_BouncedPlayers.InvalidIndex() )
  215. {
  216. if ( gpGlobals->curtime < m_BouncedPlayers[iIndex] + 4.0f )
  217. {
  218. IncrementCount();
  219. }
  220. }
  221. }
  222. }
  223. }
  224. CUtlMap< int, float > m_BouncedPlayers; // userID and most recent time they were bounced
  225. };
  226. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_BounceAndKill, ACHIEVEMENT_TF_DEMOMAN_BOUNCE_AND_KILL, "TF_DEMOMAN_BOUNCE_AND_KILL", 5 );
  227. //----------------------------------------------------------------------------------------------------------------
  228. class CAchievementTFDemoman_DecapitatePlayers : public CBaseTFAchievement
  229. {
  230. void Init()
  231. {
  232. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
  233. SetGoal( 50 );
  234. SetStoreProgressInSteam( true );
  235. }
  236. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  237. {
  238. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  239. if ( !pLocalPlayer )
  240. return;
  241. if ( pLocalPlayer != pAttacker )
  242. return;
  243. int customdmg = event->GetInt( "customkill" );
  244. if ( customdmg == TF_DMG_CUSTOM_DECAPITATION )
  245. {
  246. IncrementCount();
  247. }
  248. }
  249. };
  250. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DecapitatePlayers, ACHIEVEMENT_TF_DEMOMAN_DECAPITATE_PLAYERS, "TF_DEMOMAN_DECAPITATE_PLAYERS", 5 );
  251. //----------------------------------------------------------------------------------------------------------------
  252. class CAchievementTFDemoman_DecapitatePlayersFast : public CBaseTFAchievement
  253. {
  254. void Init()
  255. {
  256. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
  257. SetGoal( 1 );
  258. }
  259. virtual void ListenForEvents()
  260. {
  261. ListenForGameEvent( "teamplay_round_active" );
  262. ListenForGameEvent( "localplayer_respawn" );
  263. m_iTimelyDecapitations = 0;
  264. }
  265. void FireGameEvent_Internal( IGameEvent *event )
  266. {
  267. if ( FStrEq( event->GetName(), "teamplay_round_active" ) ||
  268. FStrEq( event->GetName(), "localplayer_respawn" ) )
  269. {
  270. m_iTimelyDecapitations = 0;
  271. }
  272. }
  273. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  274. {
  275. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  276. if ( !pLocalPlayer )
  277. return;
  278. if ( pLocalPlayer != pAttacker )
  279. return;
  280. int customdmg = event->GetInt( "customkill" );
  281. if ( customdmg == TF_DMG_CUSTOM_DECAPITATION )
  282. {
  283. if ( (m_iTimelyDecapitations == 0) || ((m_iTimelyDecapitations > 0) && (gpGlobals->curtime < m_flLastDecapTime + 10.f)) )
  284. {
  285. m_iTimelyDecapitations++;
  286. }
  287. else
  288. {
  289. m_iTimelyDecapitations = 1;
  290. }
  291. m_flLastDecapTime = gpGlobals->curtime;
  292. if ( m_iTimelyDecapitations == 4 )
  293. {
  294. IncrementCount();
  295. }
  296. }
  297. }
  298. int m_iTimelyDecapitations;
  299. float m_flLastDecapTime;
  300. };
  301. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DecapitatePlayersFast, ACHIEVEMENT_TF_DEMOMAN_DECAPITATE_PLAYERS_FAST, "TF_DEMOMAN_DECAPITATE_PLAYERS_FAST", 5 );
  302. //----------------------------------------------------------------------------------------------------------------
  303. class CAchievementTFSoldier_DuoDemomanKills : public CBaseTFAchievement
  304. {
  305. void Init()
  306. {
  307. SetFlags( ACH_SAVE_GLOBAL );
  308. SetGoal( 10 );
  309. SetStoreProgressInSteam( true );
  310. }
  311. virtual void ListenForEvents()
  312. {
  313. ListenForGameEvent( "player_death" );
  314. }
  315. void FireGameEvent_Internal( IGameEvent *event )
  316. {
  317. if ( FStrEq( event->GetName(), "player_death" ) )
  318. {
  319. int iAttackerIndex = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
  320. if ( iAttackerIndex == 0 )
  321. return;
  322. CTFPlayer *pAttacker = ToTFPlayer( UTIL_PlayerByIndex( iAttackerIndex ) );
  323. if ( !pAttacker )
  324. return;
  325. int iAssisterIndex = engine->GetPlayerForUserID( event->GetInt( "assister" ) );
  326. if ( iAssisterIndex == 0 )
  327. return;
  328. CTFPlayer *pAssister = ToTFPlayer( UTIL_PlayerByIndex( iAssisterIndex ) );
  329. if ( !pAssister )
  330. return;
  331. if ( pAttacker == C_BasePlayer::GetLocalPlayer() && pAssister->IsPlayerClass( TF_CLASS_DEMOMAN ) )
  332. {
  333. // We are the attacker and the assist is from a demoman.
  334. IncrementCount();
  335. return;
  336. }
  337. if ( pAssister == C_BasePlayer::GetLocalPlayer() && pAttacker->IsPlayerClass( TF_CLASS_DEMOMAN ) )
  338. {
  339. // We are the assister and the kill is from a demoman.
  340. IncrementCount();
  341. return;
  342. }
  343. }
  344. }
  345. };
  346. DECLARE_ACHIEVEMENT( CAchievementTFSoldier_DuoDemomanKills, ACHIEVEMENT_TF_DEMOMAN_DUO_DEMOMAN_KILLS, "TF_DEMOMAN_DUO_DEMOMAN_KILLS", 5 );
  347. //----------------------------------------------------------------------------------------------------------------
  348. class CAchievementTFDemoman_KillTwoDuringStickyJump : public CBaseTFAchievement
  349. {
  350. // While airborne after a sticky-jump, kill at least two enemy players
  351. void Init()
  352. {
  353. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL );
  354. SetGoal( 1 );
  355. }
  356. virtual void ListenForEvents()
  357. {
  358. ListenForGameEvent( "sticky_jump" );
  359. ListenForGameEvent( "sticky_jump_landed" );
  360. ListenForGameEvent( "teamplay_round_active" );
  361. ListenForGameEvent( "localplayer_respawn" );
  362. m_iKilledDuringStickyJump = 0;
  363. m_bStickyJumping = false;
  364. }
  365. void FireGameEvent_Internal( IGameEvent *event )
  366. {
  367. if ( FStrEq( event->GetName(), "teamplay_round_active" ) ||
  368. FStrEq( event->GetName(), "localplayer_respawn" ) )
  369. {
  370. m_iKilledDuringStickyJump = 0;
  371. m_bStickyJumping = false;
  372. }
  373. else if ( FStrEq( event->GetName(), "sticky_jump_landed" ) )
  374. {
  375. int iIndex = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
  376. if ( iIndex > 0 )
  377. {
  378. C_TFPlayer *pJumper = ToTFPlayer( UTIL_PlayerByIndex( iIndex ) );
  379. if ( pJumper && ( pJumper == C_BasePlayer::GetLocalPlayer() ) )
  380. {
  381. m_iKilledDuringStickyJump = 0;
  382. m_bStickyJumping = false;
  383. }
  384. }
  385. return;
  386. }
  387. else if ( FStrEq( event->GetName(), "sticky_jump" ) )
  388. {
  389. int iIndex = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
  390. if ( iIndex > 0 )
  391. {
  392. C_TFPlayer *pJumper = ToTFPlayer( UTIL_PlayerByIndex( iIndex ) );
  393. if ( pJumper && ( pJumper == C_BasePlayer::GetLocalPlayer() ) )
  394. {
  395. m_iKilledDuringStickyJump = 0;
  396. m_bStickyJumping = true;
  397. }
  398. }
  399. return;
  400. }
  401. }
  402. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  403. {
  404. if ( !pVictim || !pVictim->IsPlayer() )
  405. return;
  406. if ( pAttacker && ( pAttacker == C_BasePlayer::GetLocalPlayer() ) )
  407. {
  408. if ( m_bStickyJumping )
  409. {
  410. m_iKilledDuringStickyJump++;
  411. if ( m_iKilledDuringStickyJump == 2 )
  412. {
  413. IncrementCount();
  414. }
  415. }
  416. }
  417. }
  418. private:
  419. bool m_bStickyJumping;
  420. int m_iKilledDuringStickyJump;
  421. };
  422. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillTwoDuringStickyJump, ACHIEVEMENT_TF_DEMOMAN_KILL_TWO_DURING_STICKYJUMP, "TF_DEMOMAN_KILL_TWO_DURING_STICKYJUMP", 5 );
  423. //----------------------------------------------------------------------------------------------------------------
  424. class CAchievementTFDemoman_KillPlayerAfterTeleport : public CBaseTFAchievement
  425. {
  426. // Kill an enemy player within X seconds of them teleporting in
  427. void Init()
  428. {
  429. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL );
  430. SetGoal( 1 );
  431. }
  432. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  433. {
  434. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  435. if ( !pLocalPlayer )
  436. return;
  437. if ( !pVictim || !pVictim->IsPlayer() )
  438. return;
  439. C_TFPlayer *pTFVictim = ToTFPlayer( pVictim );
  440. if ( event->GetInt( "weaponid" ) == TF_WEAPON_GRENADE_PIPEBOMB )
  441. {
  442. if ( pTFVictim->m_Shared.InCond( TF_COND_TELEPORTED ) && ( gpGlobals->curtime - pTFVictim->m_Shared.GetTimeTeleEffectAdded() <= 5.0 ) )
  443. {
  444. IncrementCount();
  445. }
  446. }
  447. }
  448. };
  449. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillPlayerAfterTeleport, ACHIEVEMENT_TF_DEMOMAN_KILL_PLAYER_AFTER_TP, "TF_DEMOMAN_KILL_PLAYER_AFTER_TP", 5 );
  450. //----------------------------------------------------------------------------------------------------------------
  451. class CAchievementTFDemoman_DominateEngineerThreeTimes : public CBaseTFAchievement
  452. {
  453. // Dominate three Engineers
  454. void Init()
  455. {
  456. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL );
  457. SetGoal( 3 );
  458. SetStoreProgressInSteam( true );
  459. }
  460. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  461. {
  462. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  463. if ( !pLocalPlayer )
  464. return;
  465. if ( !pVictim || !pVictim->IsPlayer() )
  466. return;
  467. bool bDomination = event->GetInt( "death_flags" ) & TF_DEATH_DOMINATION;
  468. if ( bDomination == true )
  469. {
  470. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  471. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_ENGINEER ) )
  472. {
  473. IncrementCount();
  474. }
  475. }
  476. }
  477. };
  478. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DominateEngineerThreeTimes, ACHIEVEMENT_TF_DEMOMAN_DOMINATE_THREE_ENGINEERS, "TF_DEMOMAN_DOMINATE_THREE_ENGINEERS", 5 );
  479. //----------------------------------------------------------------------------------------------------------------
  480. class CAchievementTFDemoman_KillBuildingDirectHit : public CBaseTFAchievement
  481. {
  482. // Kill an Engineer building that you can't see with a direct hit from your Grenade Launcher
  483. // Server awards this achievement (tf_obj.cpp) - no other code necessary
  484. void Init()
  485. {
  486. SetFlags( ACH_SAVE_GLOBAL );
  487. SetGoal( 1 );
  488. }
  489. };
  490. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillBuildingDirectHit, ACHIEVEMENT_TF_DEMOMAN_KILL_BUILDING_DIRECT_HIT, "TF_DEMOMAN_KILL_BUILDING_DIRECT_HIT", 5 );
  491. //----------------------------------------------------------------------------------------------------------------
  492. class CAchievementTFDemoman_MeleeKillWhileJumping : public CBaseTFAchievement
  493. {
  494. // Get a melee kill while in sticky jump
  495. void Init()
  496. {
  497. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  498. SetGoal( 1 );
  499. }
  500. virtual void ListenForEvents()
  501. {
  502. ListenForGameEvent( "sticky_jump" );
  503. ListenForGameEvent( "sticky_jump_landed" );
  504. ListenForGameEvent( "teamplay_round_active" );
  505. ListenForGameEvent( "localplayer_respawn" );
  506. m_bStickyJumping = false;
  507. }
  508. void FireGameEvent_Internal( IGameEvent *event )
  509. {
  510. if ( FStrEq( event->GetName(), "teamplay_round_active" ) ||
  511. FStrEq( event->GetName(), "localplayer_respawn" ) )
  512. {
  513. m_bStickyJumping = false;
  514. }
  515. else if ( FStrEq( event->GetName(), "sticky_jump_landed" ) )
  516. {
  517. int iIndex = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
  518. if ( iIndex > 0 )
  519. {
  520. C_TFPlayer *pJumper = ToTFPlayer( UTIL_PlayerByIndex( iIndex ) );
  521. if ( pJumper && ( pJumper == C_BasePlayer::GetLocalPlayer() ) )
  522. {
  523. m_bStickyJumping = false;
  524. }
  525. }
  526. return;
  527. }
  528. else if ( FStrEq( event->GetName(), "sticky_jump" ) )
  529. {
  530. int iIndex = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
  531. if ( iIndex > 0 )
  532. {
  533. C_TFPlayer *pJumper = ToTFPlayer( UTIL_PlayerByIndex( iIndex ) );
  534. if ( pJumper && ( pJumper == C_BasePlayer::GetLocalPlayer() ) )
  535. {
  536. m_bStickyJumping = true;
  537. }
  538. }
  539. return;
  540. }
  541. }
  542. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  543. {
  544. if ( !pVictim || !pVictim->IsPlayer() )
  545. return;
  546. if ( pAttacker && ( pAttacker == C_BasePlayer::GetLocalPlayer() ) )
  547. {
  548. if ( m_bStickyJumping )
  549. {
  550. if ( event->GetInt( "weaponid" ) == TF_WEAPON_BOTTLE || event->GetInt( "weaponid" ) == TF_WEAPON_SWORD )
  551. {
  552. IncrementCount();
  553. }
  554. }
  555. }
  556. }
  557. private:
  558. bool m_bStickyJumping;
  559. };
  560. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_MeleeKillWhileJumping, ACHIEVEMENT_TF_DEMOMAN_MELEE_KILL_WHILE_STICKYJUMPING, "TF_DEMOMAN_MELEE_KILL_WHILE_STICKYJUMPING", 5 );
  561. //----------------------------------------------------------------------------------------------------------------
  562. class CAchievementTFDemoman_KillEngiSentryDispenser : public CBaseTFAchievement
  563. {
  564. // Kill an Engineer, his Sentry and Dispenser, with one sticky detonation
  565. void Init()
  566. {
  567. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL );
  568. SetGoal( 1 );
  569. SetDefLessFunc( m_Engineers );
  570. SetDefLessFunc( m_SentryDestroyed );
  571. SetDefLessFunc( m_DispenserDestroyed );
  572. ResetTracking();
  573. }
  574. virtual void ListenForEvents()
  575. {
  576. ListenForGameEvent( "teamplay_round_active" );
  577. ListenForGameEvent( "localplayer_respawn" );
  578. ListenForGameEvent( "object_destroyed" );
  579. ResetTracking();
  580. }
  581. void FireGameEvent_Internal( IGameEvent *event )
  582. {
  583. if ( FStrEq( event->GetName(), "teamplay_round_active" ) ||
  584. FStrEq( event->GetName(), "localplayer_respawn" ) )
  585. {
  586. ResetTracking();
  587. }
  588. else if ( FStrEq( event->GetName(), "object_destroyed" ) )
  589. {
  590. if ( event->GetInt( "weaponid" ) == TF_WEAPON_GRENADE_PIPEBOMB )
  591. {
  592. int iAttacker = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
  593. CBaseEntity *pAttacker = UTIL_PlayerByIndex( iAttacker );
  594. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  595. if ( !pLocalPlayer )
  596. return;
  597. if ( pLocalPlayer != pAttacker )
  598. return;
  599. int iEngineer = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
  600. int iObject = event->GetInt( "objecttype" );
  601. if ( iObject == OBJ_SENTRYGUN )
  602. {
  603. int iIndex = m_SentryDestroyed.Find( iEngineer );
  604. if ( iIndex != m_SentryDestroyed.InvalidIndex() )
  605. {
  606. // already tracking them, update the time
  607. m_SentryDestroyed[iIndex] = gpGlobals->curtime;
  608. }
  609. else
  610. {
  611. m_SentryDestroyed.Insert( iEngineer, gpGlobals->curtime );
  612. }
  613. CheckGoalMet();
  614. }
  615. if ( iObject == OBJ_DISPENSER )
  616. {
  617. int iIndex = m_DispenserDestroyed.Find( iEngineer );
  618. if ( iIndex != m_DispenserDestroyed.InvalidIndex() )
  619. {
  620. // already tracking them, update the time
  621. m_DispenserDestroyed[iIndex] = gpGlobals->curtime;
  622. }
  623. else
  624. {
  625. m_DispenserDestroyed.Insert( iEngineer, gpGlobals->curtime );
  626. }
  627. CheckGoalMet();
  628. }
  629. }
  630. }
  631. }
  632. void ResetTracking( void )
  633. {
  634. m_Engineers.RemoveAll();
  635. m_SentryDestroyed.RemoveAll();
  636. m_DispenserDestroyed.RemoveAll();
  637. }
  638. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  639. {
  640. if ( event->GetInt( "weaponid" ) == TF_WEAPON_GRENADE_PIPEBOMB )
  641. {
  642. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  643. if ( !pLocalPlayer )
  644. return;
  645. if ( !pVictim || !pVictim->IsPlayer() )
  646. return;
  647. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  648. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_ENGINEER ) )
  649. {
  650. int iEngineer = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
  651. m_Engineers.InsertOrReplace( iEngineer, gpGlobals->curtime );
  652. CheckGoalMet();
  653. }
  654. }
  655. }
  656. void CheckGoalMet( void )
  657. {
  658. FOR_EACH_MAP_FAST ( m_Engineers, numEngineers )
  659. {
  660. int iEngineer = m_Engineers.Key( numEngineers );
  661. // Destroyed their Sentry?
  662. int iSentry = m_SentryDestroyed.Find( iEngineer );
  663. if ( iSentry != m_SentryDestroyed.InvalidIndex() )
  664. {
  665. // Destroyed their Dispenser?
  666. int iDispenser = m_DispenserDestroyed.Find( iEngineer );
  667. if ( iDispenser != m_DispenserDestroyed.InvalidIndex() )
  668. {
  669. // All three at the same time?
  670. // if ( ( m_Engineers[numEngineers] == m_SentryDestroyed[iSentry] ) &&
  671. // ( m_Engineers[numEngineers] == m_DispenserDestroyed[iDispenser] ) )
  672. if ( ( gpGlobals->curtime < m_SentryDestroyed[iSentry] + 0.1f ) &&
  673. ( gpGlobals->curtime < m_DispenserDestroyed[iDispenser] + 0.1f ) &&
  674. ( gpGlobals->curtime < m_Engineers[numEngineers] + 0.1f ) )
  675. {
  676. IncrementCount();
  677. }
  678. }
  679. }
  680. }
  681. }
  682. private:
  683. CUtlMap< int, float > m_SentryDestroyed; // Engineer userID and time sentry was destroyed
  684. CUtlMap< int, float > m_DispenserDestroyed; // Engineer userID and time dispenser was destroyed
  685. CUtlMap< int, float > m_Engineers; // Engineers we've killed and the time
  686. };
  687. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillEngiSentryDispenser, ACHIEVEMENT_TF_DEMOMAN_KILL_ENGI_SENTRY_DISPENSER, "TF_DEMOMAN_KILL_ENGI_SENTRY_DISPENSER", 5 );
  688. //----------------------------------------------------------------------------------------------------------------
  689. class CAchievementTFDemoman_DecapitateEqualizer : public CBaseTFAchievement
  690. {
  691. void Init()
  692. {
  693. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL );
  694. SetGoal( 1 );
  695. }
  696. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  697. {
  698. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  699. if ( !pTFVictim )
  700. return;
  701. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SOLDIER ) )
  702. {
  703. CTFShovel *pShovel = dynamic_cast<CTFShovel*>( pTFVictim->GetActiveTFWeapon() );
  704. if ( pShovel && (pShovel->GetShovelType() == SHOVEL_DAMAGE_BOOST) )
  705. {
  706. int customdmg = event->GetInt( "customkill" );
  707. if ( customdmg == TF_DMG_CUSTOM_DECAPITATION )
  708. {
  709. IncrementCount();
  710. }
  711. }
  712. }
  713. }
  714. };
  715. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DecapitateEqualizer, ACHIEVEMENT_TF_DEMOMAN_DECAPITATE_EQUALIZER, "TF_DEMOMAN_DECAPITATE_EQUALIZER", 5 );
  716. //----------------------------------------------------------------------------------------------------------------
  717. class CAchievementTFDemoman_DecapitateNemesis : public CBaseTFAchievement
  718. {
  719. void Init()
  720. {
  721. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL );
  722. SetGoal( 1 );
  723. }
  724. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  725. {
  726. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  727. if ( !pTFVictim )
  728. return;
  729. if ( pTFVictim && pTFVictim->IsNemesisOfLocalPlayer() )
  730. {
  731. int customdmg = event->GetInt( "customkill" );
  732. if ( customdmg == TF_DMG_CUSTOM_DECAPITATION )
  733. {
  734. IncrementCount();
  735. }
  736. }
  737. }
  738. };
  739. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DecapitateNemesis, ACHIEVEMENT_TF_DEMOMAN_DECAPITATE_NEMESIS, "TF_DEMOMAN_DECAPITATE_NEMESIS", 5 );
  740. //----------------------------------------------------------------------------------------------------------------
  741. class CAchievementTFDemoman_DamageGrind : public CBaseTFAchievement
  742. {
  743. void Init()
  744. {
  745. SetFlags( ACH_SAVE_GLOBAL );
  746. SetGoal( 1000000 );
  747. SetStoreProgressInSteam( true );
  748. }
  749. void OnPlayerStatsUpdate()
  750. {
  751. ClassStats_t &classStats = CTFStatPanel::GetClassStats( TF_CLASS_DEMOMAN );
  752. int iOldCount = m_iCount;
  753. m_iCount = classStats.accumulated.m_iStat[TFSTAT_BLASTDAMAGE];
  754. if ( m_iCount != iOldCount )
  755. {
  756. m_pAchievementMgr->SetDirty( true );
  757. }
  758. if ( IsLocalTFPlayerClass( TF_CLASS_DEMOMAN ) )
  759. {
  760. EvaluateNewAchievement();
  761. }
  762. }
  763. };
  764. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DamageGrind, ACHIEVEMENT_TF_DEMOMAN_DAMAGE_GRIND, "TF_DEMOMAN_DAMAGE_GRIND", 5 );
  765. //----------------------------------------------------------------------------------------------------------------
  766. class CAchievementTFDemoman_KillXCapping : public CBaseTFAchievement
  767. {
  768. // Kill "x" players that are capping or pushing the cart with one detonation, "y" times
  769. // Server checks for this achievement - no code necessary
  770. void Init()
  771. {
  772. SetFlags( ACH_SAVE_GLOBAL );
  773. SetGoal( 3 );
  774. SetStoreProgressInSteam( true );
  775. }
  776. };
  777. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillXCapping, ACHIEVEMENT_TF_DEMOMAN_KILL_X_CAPPING_ONEDET, "TF_DEMOMAN_KILL_X_CAPPING_ONEDET", 5 );
  778. //----------------------------------------------------------------------------------------------------------------
  779. class CAchievementTFDemoman_KillXDefending : public CBaseTFAchievement
  780. {
  781. // Kill "x" players that are defending
  782. // Server checks for this achievement - no code necessary
  783. void Init()
  784. {
  785. SetFlags( ACH_SAVE_GLOBAL );
  786. SetGoal( 25 );
  787. SetStoreProgressInSteam( true );
  788. }
  789. };
  790. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillXDefending, ACHIEVEMENT_TF_DEMOMAN_KILL_X_DEFENDING, "TF_DEMOMAN_KILL_X_DEFENDING", 5 );
  791. //----------------------------------------------------------------------------------------------------------------
  792. class CAchievementTFDemoman_DestroyBuildings : public CBaseTFAchievement
  793. {
  794. // Destroy "x" buildings
  795. void Init()
  796. {
  797. SetFlags( ACH_SAVE_GLOBAL );
  798. SetGoal( 50 );
  799. SetStoreProgressInSteam( true );
  800. }
  801. virtual void ListenForEvents()
  802. {
  803. ListenForGameEvent( "object_destroyed" );
  804. }
  805. void FireGameEvent_Internal( IGameEvent *event )
  806. {
  807. if ( FStrEq( event->GetName(), "object_destroyed" ) )
  808. {
  809. int iIndex = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
  810. CBaseEntity *pDestroyer = UTIL_PlayerByIndex( iIndex );
  811. C_TFPlayer *pTFPlayer = C_TFPlayer::GetLocalTFPlayer();
  812. if ( pDestroyer == pTFPlayer )
  813. {
  814. IncrementCount();
  815. }
  816. }
  817. }
  818. };
  819. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DestroyBuildings, ACHIEVEMENT_TF_DEMOMAN_DESTROY_BUILDINGS_GRIND, "TF_DEMOMAN_DESTROY_BUILDINGS_GRIND", 5 );
  820. //----------------------------------------------------------------------------------------------------------------
  821. class CAchievementTFDemoman_KillXHeaviesAtFull : public CBaseTFAchievement
  822. {
  823. // Kill 3 Heavies from full health with a single Sticky detonation
  824. // Server checks for this achievement - no code necessary
  825. void Init()
  826. {
  827. SetFlags( ACH_SAVE_GLOBAL );
  828. SetGoal( 3 );
  829. SetStoreProgressInSteam( true );
  830. }
  831. };
  832. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillXHeaviesAtFull, ACHIEVEMENT_TF_DEMOMAN_KILL_X_HEAVIES_FULLHP_ONEDET, "TF_DEMOMAN_KILL_X_HEAVIES_FULLHP_ONEDET", 5 );
  833. //----------------------------------------------------------------------------------------------------------------
  834. class CAchievementTFDemoman_KillXScoutsPyros : public CBaseTFAchievement
  835. {
  836. // Kill 25 Scouts or Pyros with the grenade launcher
  837. void Init()
  838. {
  839. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL );
  840. SetGoal( 25 );
  841. SetStoreProgressInSteam( true );
  842. }
  843. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  844. {
  845. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  846. if ( !pLocalPlayer )
  847. return;
  848. if ( !pVictim || !pVictim->IsPlayer() )
  849. return;
  850. C_TFPlayer *pTFVictim = ToTFPlayer( pVictim );
  851. if ( pTFVictim->IsPlayerClass( TF_CLASS_PYRO ) || pTFVictim->IsPlayerClass( TF_CLASS_SCOUT ) )
  852. {
  853. if ( event->GetInt( "weaponid" ) == TF_WEAPON_GRENADE_DEMOMAN )
  854. {
  855. IncrementCount();
  856. }
  857. }
  858. }
  859. };
  860. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillXScoutsPyros, ACHIEVEMENT_TF_DEMOMAN_KILL_X_SCOUTS_PYROS, "TF_DEMOMAN_KILL_X_SCOUTS_PYROS", 5 );
  861. //----------------------------------------------------------------------------------------------------------------
  862. class CAchievementTFDemoman_TauntKill : public CBaseTFAchievement
  863. {
  864. void Init()
  865. {
  866. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER );
  867. SetGoal( 1 );
  868. }
  869. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  870. {
  871. // was this a taunt kill?
  872. if ( event->GetInt( "customkill" ) == TF_DMG_CUSTOM_TAUNTATK_BARBARIAN_SWING )
  873. {
  874. IncrementCount();
  875. }
  876. }
  877. };
  878. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_TauntKill, ACHIEVEMENT_TF_DEMOMAN_TAUNT_KILL, "TF_DEMOMAN_TAUNT_KILL", 5 );
  879. //----------------------------------------------------------------------------------------------------------------
  880. class CAchievementTFDemoman_ChargeKill : public CBaseTFAchievement
  881. {
  882. void Init()
  883. {
  884. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER );
  885. SetGoal( 1 );
  886. }
  887. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  888. {
  889. // was this a taunt kill?
  890. if ( event->GetInt( "customkill" ) == TF_DMG_CUSTOM_CHARGE_IMPACT )
  891. {
  892. IncrementCount();
  893. }
  894. }
  895. };
  896. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_ChargeKill, ACHIEVEMENT_TF_DEMOMAN_CHARGE_KILL, "TF_DEMOMAN_CHARGE_KILL", 5 );
  897. //----------------------------------------------------------------------------------------------------------------
  898. class CAchievementTFDemoman_CritSwordKill : public CBaseTFAchievement
  899. {
  900. void Init()
  901. {
  902. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER );
  903. SetGoal( 5 );
  904. SetStoreProgressInSteam( true );
  905. }
  906. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  907. {
  908. // was this a charge kill with the sword?
  909. int nDamageBits = event->GetInt( "damagebits" );
  910. if ( (nDamageBits & DMG_CRITICAL) && (event->GetInt( "customkill" ) == TF_DMG_CUSTOM_DECAPITATION) )
  911. {
  912. IncrementCount();
  913. }
  914. }
  915. };
  916. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_CritSwordKill, ACHIEVEMENT_TF_DEMOMAN_CRIT_SWORD_KILL, "TF_DEMOMAN_CRIT_SWORD_KILL", 5 );
  917. //----------------------------------------------------------------------------------------------------------------
  918. class CAchievementTFDemoman_AirBurstKills : public CBaseTFAchievement
  919. {
  920. void Init()
  921. {
  922. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER );
  923. SetGoal( 30 );
  924. SetStoreProgressInSteam( true );
  925. }
  926. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  927. {
  928. // was this an air burst kill?
  929. if ( event->GetInt( "customkill" ) == TF_DMG_CUSTOM_AIR_STICKY_BURST )
  930. {
  931. IncrementCount();
  932. }
  933. }
  934. };
  935. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_AirBurstKills, ACHIEVEMENT_TF_DEMOMAN_AIR_BURST_KILLS, "TF_DEMOMAN_AIR_BURST_KILLS", 5 );
  936. //----------------------------------------------------------------------------------------------------------------
  937. class CAchievementTFDemoman_StickyJumpCap : public CBaseTFAchievement
  938. {
  939. void Init()
  940. {
  941. SetFlags( ACH_SAVE_GLOBAL | ACH_FILTER_ATTACKER_IS_PLAYER );
  942. SetGoal( 1 );
  943. }
  944. virtual void ListenForEvents( void )
  945. {
  946. ListenForGameEvent( "teamplay_round_active" );
  947. ListenForGameEvent( "teamplay_point_startcapture" );
  948. ListenForGameEvent( "controlpoint_endtouch" );
  949. ListenForGameEvent( "teamplay_point_captured" );
  950. ListenForGameEvent( "sticky_jump_landed" );
  951. ResetTracking();
  952. }
  953. void CheckGoalMet( void )
  954. {
  955. // If sticky_jump_landed and startcapture times occurred roughly together...
  956. float fTemp1 = 0;
  957. float fTemp2 = 0;
  958. if ( m_fLandTime > m_fCapStartTime )
  959. {
  960. fTemp1 = m_fLandTime;
  961. fTemp2 = m_fCapStartTime;
  962. }
  963. else
  964. {
  965. fTemp1 = m_fCapStartTime;
  966. fTemp2 = m_fLandTime;
  967. }
  968. float fDelta = fTemp1 - fTemp2;
  969. if ( fDelta <= 0.5f )
  970. {
  971. // Check if we successfully capped the point we landed on
  972. if ( m_bCapped )
  973. {
  974. IncrementCount();
  975. }
  976. }
  977. }
  978. void ResetTracking( void )
  979. {
  980. m_bCapped = false;
  981. m_fLandTime = 0;
  982. m_fCapStartTime = 0;
  983. m_iCapID = -1;
  984. }
  985. void FireGameEvent_Internal( IGameEvent *event )
  986. {
  987. // Only check CP maps
  988. if ( TFGameRules() && TFGameRules()->GetGameType() != TF_GAMETYPE_CP && TFGameRules()->GetGameType() != TF_GAMETYPE_ARENA )
  989. return;
  990. // Capture the time we land
  991. if ( FStrEq( event->GetName(), "sticky_jump_landed" ) )
  992. {
  993. int iIndex = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
  994. if ( iIndex > 0 )
  995. {
  996. C_TFPlayer *pJumper = ToTFPlayer( UTIL_PlayerByIndex( iIndex ) );
  997. if ( pJumper && ( pJumper == C_BasePlayer::GetLocalPlayer() ) )
  998. {
  999. m_fLandTime = gpGlobals->curtime;
  1000. CheckGoalMet();
  1001. }
  1002. }
  1003. return;
  1004. }
  1005. // Capture the time we start capping
  1006. else if ( FStrEq( event->GetName(), "teamplay_point_startcapture" ) )
  1007. {
  1008. const char *cappers = event->GetString( "cappers" );
  1009. for ( int i = 0; i < Q_strlen( cappers ); i++ )
  1010. {
  1011. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  1012. if ( !pLocalPlayer )
  1013. return;
  1014. int iPlayerIndex = (int) cappers[i];
  1015. CTFPlayer *pCapper = ToTFPlayer( UTIL_PlayerByIndex( iPlayerIndex ) );
  1016. if ( pCapper && ( pCapper == C_BasePlayer::GetLocalPlayer() ) )
  1017. {
  1018. m_fCapStartTime = gpGlobals->curtime;
  1019. m_iCapID = event->GetInt( "cp" );
  1020. CheckGoalMet();
  1021. }
  1022. }
  1023. }
  1024. else if ( FStrEq( event->GetName(), "teamplay_point_captured" ) )
  1025. {
  1026. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  1027. if ( !pLocalPlayer )
  1028. return;
  1029. int iTeam = event->GetInt( "team" );
  1030. if ( iTeam == pLocalPlayer->GetTeamNumber() )
  1031. {
  1032. const char *cappers = event->GetString( "cappers" );
  1033. for ( int i = 0; i < Q_strlen( cappers ); i++ )
  1034. {
  1035. int iPlayerIndex = (int) cappers[i];
  1036. CTFPlayer *pCapper = ToTFPlayer( UTIL_PlayerByIndex( iPlayerIndex ) );
  1037. if ( pCapper && ( pCapper == C_BasePlayer::GetLocalPlayer() ) )
  1038. {
  1039. if ( m_iCapID == event->GetInt( "cp" ) )
  1040. {
  1041. m_bCapped = true;
  1042. CheckGoalMet();
  1043. }
  1044. }
  1045. }
  1046. }
  1047. }
  1048. else if ( FStrEq( event->GetName(), "controlpoint_endtouch" ) )
  1049. {
  1050. int iPlayerIndex = event->GetInt( "player", 0 );
  1051. if ( iPlayerIndex == GetLocalPlayerIndex() )
  1052. {
  1053. // We failed to take the point
  1054. ResetTracking();
  1055. }
  1056. }
  1057. else if ( FStrEq( event->GetName(), "teamplay_round_active" ) )
  1058. {
  1059. // Reset tracking at the start of a new round
  1060. ResetTracking();
  1061. }
  1062. }
  1063. private:
  1064. float m_fLandTime;
  1065. float m_fCapStartTime;
  1066. bool m_bCapped;
  1067. int m_iCapID;
  1068. };
  1069. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_StickyJumpCap, ACHIEVEMENT_TF_DEMOMAN_STICKYJUMP_CAP, "TF_DEMOMAN_STICKYJUMP_CAP", 5 );
  1070. //----------------------------------------------------------------------------------------------------------------
  1071. class CAchievementTFDemoman_FreezeTaunt : public CBaseTFAchievement
  1072. {
  1073. void Init()
  1074. {
  1075. SetFlags( ACH_SAVE_GLOBAL );
  1076. SetGoal( 1 );
  1077. }
  1078. // Give opponents freezecams of you taunting
  1079. // server awards this achievement, no other code within achievement necessary
  1080. };
  1081. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_FreezeTaunt, ACHIEVEMENT_TF_DEMOMAN_FREEZECAM_SMILE, "TF_DEMOMAN_FREEZECAM_SMILE", 5 );
  1082. //----------------------------------------------------------------------------------------------------------------
  1083. class CAchievementTFDemoman_FreezeTauntRump : public CBaseTFAchievement
  1084. {
  1085. void Init()
  1086. {
  1087. SetFlags( ACH_SAVE_GLOBAL );
  1088. SetGoal( 1 );
  1089. }
  1090. // Give opponents freezecams of you taunting
  1091. // server awards this achievement, no other code within achievement necessary
  1092. };
  1093. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_FreezeTauntRump, ACHIEVEMENT_TF_DEMOMAN_FREEZECAM_RUMP, "TF_DEMOMAN_FREEZECAM_RUMP", 5 );
  1094. //----------------------------------------------------------------------------------------------------------------
  1095. class CAchievementTFDemoman_EnvironmentalKill : public CBaseTFAchievement
  1096. {
  1097. void Init()
  1098. {
  1099. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_KILL_ENEMY_EVENTS );
  1100. SetGoal( 1 );
  1101. }
  1102. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1103. {
  1104. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  1105. if ( !pTFVictim )
  1106. return;
  1107. CTFPlayer *pLocalPlayer = ToTFPlayer( CBasePlayer::GetLocalPlayer() );
  1108. if ( !pLocalPlayer )
  1109. return;
  1110. if ( pTFVictim->m_Shared.GetWeaponKnockbackID() == pLocalPlayer->GetUserID() )
  1111. {
  1112. int custom = event->GetInt( "customkill" );
  1113. int damagebits = event->GetInt( "damagebits" );
  1114. if ( ( damagebits & DMG_VEHICLE ) || // They were hit by a freakin' train!
  1115. ( pAttacker && pAttacker->IsBrushModel() ) || // They were smashed by the world! Gah!
  1116. ( !pAttacker || (pAttacker == pVictim) ) || // He killed himself!
  1117. ( custom == TF_DMG_CUSTOM_SUICIDE ) ||
  1118. ( custom == TF_DMG_CUSTOM_TRIGGER_HURT ) ) // A trigger-hurt got him!
  1119. {
  1120. IncrementCount();
  1121. }
  1122. }
  1123. }
  1124. };
  1125. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_EnvironmentalKill, ACHIEVEMENT_TF_DEMOMAN_ENVIRONMENTAL_KILL, "TF_DEMOMAN_ENVIRONMENTAL_KILL", 5 );
  1126. //----------------------------------------------------------------------------------------------------------------
  1127. class CAchievementTFDemoman_DestroyStickyBombs : public CBaseTFAchievement
  1128. {
  1129. // Destroy X stickybombs with the Scottish Defender
  1130. void Init()
  1131. {
  1132. SetFlags( ACH_SAVE_GLOBAL );
  1133. SetGoal( 100 );
  1134. SetStoreProgressInSteam( true );
  1135. }
  1136. };
  1137. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DestroyStickyBombs, ACHIEVEMENT_TF_DEMOMAN_DESTROY_X_STICKYBOMBS, "TF_DEMOMAN_DESTROY_X_STICKYBOMBS", 5 );
  1138. //----------------------------------------------------------------------------------------------------------------
  1139. class CAchievementTFDemoman_StickyJumpDistance : public CBaseTFAchievement
  1140. {
  1141. DECLARE_CLASS( CAchievementTFDemoman_StickyJumpDistance, CBaseTFAchievement );
  1142. void Init()
  1143. {
  1144. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_KILL_EVENTS );
  1145. SetGoal( 1 );
  1146. ResetTracking();
  1147. }
  1148. virtual bool IsActive()
  1149. {
  1150. return BaseClass::IsActive();
  1151. }
  1152. virtual void ListenForEvents()
  1153. {
  1154. ListenForGameEvent( "teamplay_round_active" );
  1155. ListenForGameEvent( "localplayer_respawn" );
  1156. ListenForGameEvent( "sticky_jump" );
  1157. ListenForGameEvent( "sticky_jump_landed" );
  1158. ResetTracking();
  1159. }
  1160. void ResetTracking( void )
  1161. {
  1162. ClearThink();
  1163. m_vecStartJump = vec3_origin;
  1164. }
  1165. void CheckJump( void )
  1166. {
  1167. CTFPlayer *pLocalTFPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  1168. if ( pLocalTFPlayer )
  1169. {
  1170. // someone has messed with gravity, so reset our tracking
  1171. if ( GetCurrentGravity() != 800.0f )
  1172. {
  1173. ResetTracking();
  1174. return;
  1175. }
  1176. Vector vecCurrent = pLocalTFPlayer->GetAbsOrigin();
  1177. vecCurrent.z = 0;
  1178. float flDistSqr = (vecCurrent - m_vecStartJump).Length2DSqr();
  1179. if ( flDistSqr > (2048 * 2048) )
  1180. {
  1181. IncrementCount();
  1182. }
  1183. }
  1184. }
  1185. void FireGameEvent_Internal( IGameEvent *event )
  1186. {
  1187. const char *pszEvent = event->GetName();
  1188. if ( FStrEq( pszEvent, "teamplay_round_active" ) ||
  1189. FStrEq( pszEvent, "localplayer_respawn" ) )
  1190. {
  1191. ResetTracking();
  1192. }
  1193. else if ( FStrEq( pszEvent, "sticky_jump" ) )
  1194. {
  1195. int iUserID = event->GetInt( "userid" );
  1196. CTFPlayer *pLocalTFPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  1197. if ( pLocalTFPlayer && pLocalTFPlayer->GetUserID() == iUserID )
  1198. {
  1199. m_vecStartJump = pLocalTFPlayer->GetAbsOrigin();
  1200. m_vecStartJump.z = 0;
  1201. SetNextThink( 0.1 );
  1202. }
  1203. }
  1204. else if ( FStrEq( pszEvent, "sticky_jump_landed" ) )
  1205. {
  1206. int iUserID = event->GetInt( "userid" );
  1207. CTFPlayer *pLocalTFPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  1208. if ( pLocalTFPlayer && pLocalTFPlayer->GetUserID() == iUserID )
  1209. {
  1210. CheckJump();
  1211. ResetTracking();
  1212. }
  1213. }
  1214. }
  1215. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1216. {
  1217. if ( !pVictim || !pVictim->IsPlayer() )
  1218. return;
  1219. if ( pVictim == C_BasePlayer::GetLocalPlayer() )
  1220. {
  1221. ResetTracking();
  1222. }
  1223. }
  1224. virtual void Think( void )
  1225. {
  1226. CheckJump();
  1227. SetNextThink( 0.1 );
  1228. }
  1229. private:
  1230. Vector m_vecStartJump;
  1231. };
  1232. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_StickyJumpDistance, ACHIEVEMENT_TF_DEMOMAN_STICKJUMP_DISTANCE, "TF_DEMOMAN_STICKJUMP_DISTANCE", 5 );
  1233. //----------------------------------------------------------------------------------------------------------------
  1234. class CAchievementTFDemoman_Kill3WithDetonation : public CBaseTFAchievement
  1235. {
  1236. // Destroy 3 players with a single pipebomb
  1237. void Init()
  1238. {
  1239. SetFlags( ACH_SAVE_GLOBAL );
  1240. SetGoal( 1 );
  1241. }
  1242. };
  1243. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_Kill3WithDetonation, ACHIEVEMENT_TF_DEMOMAN_KILL3_WITH_DETONATION, "TF_DEMOMAN_KILL3_WITH_DETONATION", 5 );
  1244. //----------------------------------------------------------------------------------------------------------------
  1245. class CAchievementTFDemoman_KillXSappingSpies : public CBaseTFAchievement
  1246. {
  1247. void Init()
  1248. {
  1249. SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
  1250. SetGoal( 20 );
  1251. SetStoreProgressInSteam( true );
  1252. }
  1253. virtual void ListenForEvents()
  1254. {
  1255. ListenForGameEvent( "player_sapped_object" );
  1256. m_hTargets.Purge();
  1257. }
  1258. int FindSpyInList( int iUserID )
  1259. {
  1260. for ( int i = m_hTargets.Count() - 1; i >= 0; i-- )
  1261. {
  1262. if ( m_hTargets[i].flTime < gpGlobals->curtime )
  1263. {
  1264. // time has run out on this one
  1265. m_hTargets.Remove( i );
  1266. continue;
  1267. }
  1268. if ( m_hTargets[i].nSpyUserID == iUserID )
  1269. return i;
  1270. }
  1271. return -1;
  1272. }
  1273. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1274. {
  1275. if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  1276. {
  1277. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  1278. if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SPY ) )
  1279. {
  1280. int iIndex = FindSpyInList( pTFVictim->GetUserID() );
  1281. if ( iIndex != -1 )
  1282. {
  1283. IncrementCount();
  1284. m_hTargets.Remove( iIndex );
  1285. }
  1286. }
  1287. }
  1288. }
  1289. void FireGameEvent_Internal( IGameEvent *event )
  1290. {
  1291. const char *pszEventName = event->GetName();
  1292. if ( FStrEq( pszEventName, "player_sapped_object" ) )
  1293. {
  1294. int nUserID = event->GetInt( "userid" );
  1295. int iIndex = FindSpyInList( nUserID );
  1296. if ( iIndex == -1 )
  1297. {
  1298. iIndex = m_hTargets.AddToTail();
  1299. m_hTargets[iIndex].nSpyUserID = nUserID;
  1300. }
  1301. m_hTargets[iIndex].flTime = gpGlobals->curtime + 5.0;
  1302. }
  1303. }
  1304. private:
  1305. struct targets_t
  1306. {
  1307. int nSpyUserID;
  1308. float flTime;
  1309. };
  1310. CUtlVector<targets_t> m_hTargets;
  1311. };
  1312. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillXSappingSpies, ACHIEVEMENT_TF_DEMOMAN_KILLXSAPPINGSPIES, "TF_DEMOMAN_KILLXSAPPINGSPIES", 5 );
  1313. //----------------------------------------------------------------------------------------------------------------
  1314. class CAchievementTFDemoman_Kill3WithPipeSetup : public CBaseTFAchievement
  1315. {
  1316. // Kill 3 players in separate explosions without placing new sticky bombs
  1317. void Init()
  1318. {
  1319. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL );
  1320. SetGoal( 1 );
  1321. }
  1322. virtual void ListenForEvents()
  1323. {
  1324. ResetCounts();
  1325. }
  1326. void ResetCounts()
  1327. {
  1328. m_iConsecutiveKillsWithoutRefiring = 0;
  1329. m_flPrevKillTime = 0;
  1330. m_iPipebombCount = 0;
  1331. }
  1332. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1333. {
  1334. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  1335. if ( !pLocalPlayer )
  1336. return;
  1337. if ( event->GetInt( "weaponid" ) == TF_WEAPON_GRENADE_PIPEBOMB )
  1338. {
  1339. if ( !m_iConsecutiveKillsWithoutRefiring )
  1340. {
  1341. // We're starting.
  1342. m_iConsecutiveKillsWithoutRefiring = 1;
  1343. m_flPrevKillTime = gpGlobals->curtime;
  1344. m_iPipebombCount = pLocalPlayer->GetNumActivePipebombs();
  1345. SetNextThink( 0.1 );
  1346. }
  1347. else if ( (gpGlobals->curtime - m_flPrevKillTime) > 0.2 ) // Make sure it wasn't in the same detonation
  1348. {
  1349. m_iConsecutiveKillsWithoutRefiring++;
  1350. m_flPrevKillTime = gpGlobals->curtime;
  1351. if ( m_iConsecutiveKillsWithoutRefiring >= 3 )
  1352. {
  1353. IncrementCount();
  1354. }
  1355. }
  1356. }
  1357. }
  1358. virtual void Think( void )
  1359. {
  1360. CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  1361. if ( !pLocalPlayer )
  1362. return;
  1363. int nPipes = pLocalPlayer->GetNumActivePipebombs();
  1364. if ( m_iPipebombCount < nPipes )
  1365. {
  1366. // They laid new pipes. We're done.
  1367. ResetCounts();
  1368. }
  1369. else
  1370. {
  1371. m_iPipebombCount = nPipes;
  1372. SetNextThink( 0.1 );
  1373. }
  1374. }
  1375. private:
  1376. int m_iPipebombCount;
  1377. int m_iConsecutiveKillsWithoutRefiring;
  1378. float m_flPrevKillTime;
  1379. };
  1380. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_Kill3WithPipeSetup, ACHIEVEMENT_TF_DEMOMAN_KILL3_WITH_PIPE_SETUPS, "TF_DEMOMAN_KILL3_WITH_PIPE_SETUPS", 5 );
  1381. //----------------------------------------------------------------------------------------------------------------
  1382. class CAchievementTFDemoman_AchieveProgress1 : public CAchievement_AchievedCount
  1383. {
  1384. public:
  1385. DECLARE_CLASS( CAchievementTFDemoman_AchieveProgress1, CAchievement_AchievedCount );
  1386. void Init()
  1387. {
  1388. BaseClass::Init();
  1389. SetAchievementsRequired( 5, ACHIEVEMENT_TF_DEMOMAN_START_RANGE, ACHIEVEMENT_TF_DEMOMAN_END_RANGE );
  1390. }
  1391. };
  1392. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_AchieveProgress1, ACHIEVEMENT_TF_DEMOMAN_ACHIEVE_PROGRESS1, "TF_DEMOMAN_ACHIEVE_PROGRESS1", 5 );
  1393. //----------------------------------------------------------------------------------------------------------------
  1394. class CAchievementTFDemoman_AchieveProgress2 : public CAchievement_AchievedCount
  1395. {
  1396. public:
  1397. DECLARE_CLASS( CAchievementTFDemoman_AchieveProgress2, CAchievement_AchievedCount );
  1398. void Init()
  1399. {
  1400. BaseClass::Init();
  1401. SetAchievementsRequired( 11, ACHIEVEMENT_TF_DEMOMAN_START_RANGE, ACHIEVEMENT_TF_DEMOMAN_END_RANGE );
  1402. }
  1403. };
  1404. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_AchieveProgress2, ACHIEVEMENT_TF_DEMOMAN_ACHIEVE_PROGRESS2, "TF_DEMOMAN_ACHIEVE_PROGRESS2", 5 );
  1405. //----------------------------------------------------------------------------------------------------------------
  1406. class CAchievementTFDemoman_AchieveProgress3 : public CAchievement_AchievedCount
  1407. {
  1408. public:
  1409. DECLARE_CLASS( CAchievementTFDemoman_AchieveProgress3, CAchievement_AchievedCount );
  1410. void Init()
  1411. {
  1412. BaseClass::Init();
  1413. SetAchievementsRequired( 17, ACHIEVEMENT_TF_DEMOMAN_START_RANGE, ACHIEVEMENT_TF_DEMOMAN_END_RANGE );
  1414. }
  1415. };
  1416. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_AchieveProgress3, ACHIEVEMENT_TF_DEMOMAN_ACHIEVE_PROGRESS3, "TF_DEMOMAN_ACHIEVE_PROGRESS3", 5 );
  1417. //----------------------------------------------------------------------------------------------------------------
  1418. class CAchievementTFDemoman_ParachuteKillGroup : public CBaseTFAchievement
  1419. {
  1420. public:
  1421. void Init()
  1422. {
  1423. SetFlags( ACH_LISTEN_KILL_EVENTS | ACH_SAVE_GLOBAL );
  1424. SetGoal( 1 );
  1425. ResetTracking();
  1426. }
  1427. virtual void ListenForEvents()
  1428. {
  1429. ListenForGameEvent( "parachute_deploy" );
  1430. ListenForGameEvent( "parachute_holster" );
  1431. }
  1432. void ResetTracking( void )
  1433. {
  1434. m_nKills = 0;
  1435. m_bParachuteDeployed = false;
  1436. }
  1437. void FireGameEvent_Internal( IGameEvent *event )
  1438. {
  1439. const char *pszEvent = event->GetName();
  1440. if ( FStrEq( pszEvent, "parachute_deploy" ) )
  1441. {
  1442. if ( event->GetInt( "index" ) == GetLocalPlayerIndex() )
  1443. {
  1444. ResetTracking();
  1445. m_bParachuteDeployed = true;
  1446. }
  1447. }
  1448. else if ( FStrEq( pszEvent, "parachute_holster" ) )
  1449. {
  1450. if ( event->GetInt( "index" ) == GetLocalPlayerIndex() )
  1451. {
  1452. ResetTracking();
  1453. }
  1454. }
  1455. }
  1456. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1457. {
  1458. if ( pVictim )
  1459. {
  1460. // Local player died
  1461. if ( pVictim == C_BasePlayer::GetLocalPlayer() )
  1462. {
  1463. ResetTracking();
  1464. }
  1465. else if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
  1466. {
  1467. if ( m_bParachuteDeployed )
  1468. {
  1469. m_nKills++;
  1470. if ( m_nKills >= 3 )
  1471. {
  1472. IncrementCount();
  1473. }
  1474. }
  1475. }
  1476. }
  1477. }
  1478. private:
  1479. int m_nKills;
  1480. bool m_bParachuteDeployed;
  1481. };
  1482. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_ParachuteKillGroup, ACHIEVEMENT_TF_DEMOMAN_PARACHUTE_KILL_GROUP, "TF_DEMOMAN_PARACHUTE_KILL_GROUP", 5 );
  1483. //----------------------------------------------------------------------------------------------------------------
  1484. class CAchievementTFDemoman_ParachuteDistance : public CBaseTFAchievement
  1485. {
  1486. public:
  1487. void Init()
  1488. {
  1489. SetFlags( ACH_LISTEN_KILL_EVENTS | ACH_SAVE_GLOBAL );
  1490. SetGoal( 1233619 );
  1491. SetStoreProgressInSteam( true );
  1492. ResetTracking();
  1493. }
  1494. virtual void ListenForEvents()
  1495. {
  1496. ListenForGameEvent( "parachute_deploy" );
  1497. ListenForGameEvent( "parachute_holster" );
  1498. }
  1499. void ResetTracking( void )
  1500. {
  1501. ClearThink();
  1502. m_flLastZ = 0.0;
  1503. }
  1504. void CheckHeight( void )
  1505. {
  1506. CBasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  1507. if ( pLocalPlayer )
  1508. {
  1509. float flCurrentZ = pLocalPlayer->GetAbsOrigin().z;
  1510. float flDela = m_flLastZ - flCurrentZ;
  1511. // make sure we've fallen....we may have been pushed upwards
  1512. if ( flDela > 0.0f )
  1513. {
  1514. IncrementCount( ( int )( flDela ) );
  1515. }
  1516. m_flLastZ = flCurrentZ;
  1517. }
  1518. }
  1519. void FireGameEvent_Internal( IGameEvent *event )
  1520. {
  1521. const char *pszEvent = event->GetName();
  1522. if ( FStrEq( pszEvent, "parachute_deploy" ) )
  1523. {
  1524. if ( event->GetInt( "index" ) == GetLocalPlayerIndex() )
  1525. {
  1526. CBasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  1527. if ( pLocalPlayer )
  1528. {
  1529. m_flLastZ = pLocalPlayer->GetAbsOrigin().z;
  1530. SetNextThink( 0.1 );
  1531. }
  1532. }
  1533. }
  1534. else if ( FStrEq( pszEvent, "parachute_holster" ) )
  1535. {
  1536. if ( event->GetInt( "index" ) == GetLocalPlayerIndex() )
  1537. {
  1538. ResetTracking();
  1539. }
  1540. }
  1541. }
  1542. virtual void Think( void )
  1543. {
  1544. CheckHeight();
  1545. SetNextThink( 0.1 );
  1546. }
  1547. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1548. {
  1549. // Local player died
  1550. if ( pVictim == C_BasePlayer::GetLocalPlayer() )
  1551. {
  1552. ResetTracking();
  1553. }
  1554. }
  1555. private:
  1556. float m_flLastZ;
  1557. };
  1558. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_ParachuteDistance, ACHIEVEMENT_TF_DEMOMAN_PARACHUTE_DISTANCE, "TF_DEMOMAN_PARACHUTE_DISTANCE", 5 );
  1559. //----------------------------------------------------------------------------------------------------------------
  1560. class CAchievementTFDemoman_ParachuteKillParachute : public CBaseTFAchievement
  1561. {
  1562. public:
  1563. void Init()
  1564. {
  1565. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
  1566. SetGoal( 1 );
  1567. }
  1568. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1569. {
  1570. CTFPlayer *pTFAttacker = ToTFPlayer( pAttacker );
  1571. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  1572. if ( pTFAttacker && pTFVictim && ( pTFAttacker == C_TFPlayer::GetLocalTFPlayer() ) )
  1573. {
  1574. if ( ( pTFAttacker->m_Shared.InCond( TF_COND_PARACHUTE_DEPLOYED ) ) && ( pTFVictim->m_Shared.InCond( TF_COND_PARACHUTE_DEPLOYED ) ) )
  1575. {
  1576. IncrementCount();
  1577. }
  1578. }
  1579. }
  1580. };
  1581. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_ParachuteKillParachute, ACHIEVEMENT_TF_DEMOMAN_PARACHUTE_KILL_PARACHUTE, "TF_DEMOMAN_PARACHUTE_KILL_PARACHUTE", 5 );
  1582. //----------------------------------------------------------------------------------------------------------------
  1583. class CAchievementTFDemoman_KillPlayerYouDidntSee : public CBaseTFAchievement
  1584. {
  1585. public:
  1586. void Init()
  1587. {
  1588. SetFlags( ACH_SAVE_GLOBAL );
  1589. SetGoal( 1 );
  1590. }
  1591. // server awards this achievement, no other code within achievement necessary
  1592. };
  1593. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillPlayerYouDidntSee, ACHIEVEMENT_TF_DEMOMAN_KILL_PLAYER_YOU_DIDNT_SEE, "TF_DEMOMAN_KILL_PLAYER_YOU_DIDNT_SEE", 5 );
  1594. //----------------------------------------------------------------------------------------------------------------
  1595. class CAchievementTFDemoman_QuickKills : public CBaseTFAchievement
  1596. {
  1597. public:
  1598. void Init()
  1599. {
  1600. SetFlags( ACH_SAVE_GLOBAL );
  1601. SetGoal( 1 );
  1602. }
  1603. virtual void ListenForEvents()
  1604. {
  1605. ListenForGameEvent( "kill_refills_meter" );
  1606. }
  1607. void FireGameEvent_Internal( IGameEvent *event )
  1608. {
  1609. if ( FStrEq( event->GetName(), "kill_refills_meter" ) )
  1610. {
  1611. if ( event->GetInt( "index" ) == GetLocalPlayerIndex() )
  1612. {
  1613. int iNewIndex = m_Times.AddToTail();
  1614. m_Times[iNewIndex] = gpGlobals->curtime;
  1615. // we only care about the last three times we killed someone
  1616. if ( m_Times.Count() > 3 )
  1617. {
  1618. m_Times.Remove( 0 );
  1619. }
  1620. if ( m_Times.Count() == 3 )
  1621. {
  1622. if ( m_Times.Tail() - m_Times.Head() <= 6.0 )
  1623. {
  1624. IncrementCount();
  1625. }
  1626. }
  1627. }
  1628. }
  1629. }
  1630. private:
  1631. CUtlVector< float > m_Times;
  1632. };
  1633. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_QuickKills, ACHIEVEMENT_TF_DEMOMAN_QUICK_KILLS, "TF_DEMOMAN_QUICK_KILLS", 5 );
  1634. //----------------------------------------------------------------------------------------------------------------
  1635. class CAchievementTFDemoman_ChargeKillChargingDemo : public CBaseTFAchievement
  1636. {
  1637. public:
  1638. void Init()
  1639. {
  1640. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
  1641. SetGoal( 1 );
  1642. }
  1643. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1644. {
  1645. CTFPlayer *pTFAttacker = ToTFPlayer( pAttacker );
  1646. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  1647. if ( pTFAttacker && pTFVictim && ( pTFAttacker == C_TFPlayer::GetLocalTFPlayer() ) )
  1648. {
  1649. if ( pTFAttacker->m_Shared.InCond( TF_COND_SHIELD_CHARGE ) && pTFVictim->m_Shared.InCond( TF_COND_SHIELD_CHARGE ) )
  1650. {
  1651. IncrementCount();
  1652. }
  1653. }
  1654. }
  1655. };
  1656. DECLARE_ACHIEVEMENT( CAchievementTFDemoman_ChargeKillChargingDemo, ACHIEVEMENT_TF_DEMOMAN_CHARGE_KILL_CHARGING_DEMO, "TF_DEMOMAN_CHARGE_KILL_CHARGING_DEMO", 5 );
  1657. #endif // CLIENT_DLL