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.

1495 lines
43 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 "econ_wearable.h"
  16. #include "achievements_tf.h"
  17. // NVNT include for tf2 damage
  18. #include "haptics/haptic_utils.h"
  19. CAchievementMgr g_AchievementMgrTF; // global achievement mgr for TF
  20. bool CheckWinNoEnemyCaps( IGameEvent *event, int iRole );
  21. // Grace period that we allow a player to start after level init and still consider them to be participating for the full round. This is fairly generous
  22. // because it can in some cases take a client several minutes to connect with respect to when the server considers the game underway
  23. #define TF_FULL_ROUND_GRACE_PERIOD ( 4 * 60.0f )
  24. bool IsLocalTFPlayerClass( int iClass );
  25. bool CBaseTFAchievementSimple::LocalPlayerCanEarn( void )
  26. {
  27. if ( TFGameRules() )
  28. {
  29. bool bMVMAchievement = ( m_iAchievementID >= ACHIEVEMENT_TF_MVM_START_RANGE && m_iAchievementID <= ACHIEVEMENT_TF_MVM_END_RANGE );
  30. if ( bMVMAchievement )
  31. {
  32. if ( !TFGameRules()->IsMannVsMachineMode() || ( GetLocalPlayerTeam() != TF_TEAM_PVE_DEFENDERS ) )
  33. {
  34. return false;
  35. }
  36. }
  37. else
  38. {
  39. if ( TFGameRules()->IsMannVsMachineMode() )
  40. {
  41. return false;
  42. }
  43. }
  44. }
  45. return BaseClass::LocalPlayerCanEarn();
  46. }
  47. void CBaseTFAchievementSimple::FireGameEvent( IGameEvent *event )
  48. {
  49. if ( !LocalPlayerCanEarn() )
  50. return;
  51. BaseClass::FireGameEvent( event );
  52. }
  53. bool CBaseTFAchievement::LocalPlayerCanEarn( void )
  54. {
  55. // Swallow game events if we're not allowed to earn achievements, or if the local player isn't the right class
  56. if ( !GameRulesAllowsAchievements() )
  57. {
  58. return false;
  59. }
  60. // Determine class & check it
  61. if ( m_iAchievementID >= ACHIEVEMENT_START_CLASS_SPECIFIC && m_iAchievementID <= ACHIEVEMENT_END_CLASS_SPECIFIC )
  62. {
  63. int iClass = floor( (m_iAchievementID - ACHIEVEMENT_START_CLASS_SPECIFIC) / 100.0f ) + 1;
  64. if ( !IsLocalTFPlayerClass( iClass ) )
  65. {
  66. return false;
  67. }
  68. }
  69. return BaseClass::LocalPlayerCanEarn();
  70. }
  71. //-----------------------------------------------------------------------------
  72. // Purpose:
  73. //-----------------------------------------------------------------------------
  74. void CTFAchievementFullRound::Init()
  75. {
  76. m_iFlags |= ACH_FILTER_FULL_ROUND_ONLY;
  77. }
  78. //-----------------------------------------------------------------------------
  79. // Purpose:
  80. //-----------------------------------------------------------------------------
  81. void CTFAchievementFullRound::ListenForEvents()
  82. {
  83. ListenForGameEvent( "teamplay_round_win" );
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Purpose:
  87. //-----------------------------------------------------------------------------
  88. void CTFAchievementFullRound::FireGameEvent_Internal( IGameEvent *event )
  89. {
  90. if ( 0 == Q_strcmp( event->GetName(), "teamplay_round_win" ) )
  91. {
  92. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  93. if ( pLocalPlayer )
  94. {
  95. // is the player currently on a game team?
  96. int iTeam = pLocalPlayer->GetTeamNumber();
  97. if ( iTeam >= FIRST_GAME_TEAM )
  98. {
  99. float flRoundTime = event->GetFloat( "round_time", 0 );
  100. if ( flRoundTime > 0 )
  101. {
  102. Event_OnRoundComplete( flRoundTime, event );
  103. }
  104. }
  105. }
  106. }
  107. }
  108. //-----------------------------------------------------------------------------
  109. // Purpose:
  110. //-----------------------------------------------------------------------------
  111. bool CTFAchievementFullRound::PlayerWasInEntireRound( float flRoundTime )
  112. {
  113. float flTeamplayStartTime = m_pAchievementMgr->GetTeamplayStartTime();
  114. if ( flTeamplayStartTime > 0 )
  115. {
  116. // has the player been present and on a game team since the start of this round (minus a grace period)?
  117. if ( flTeamplayStartTime < ( gpGlobals->curtime - flRoundTime ) + TF_FULL_ROUND_GRACE_PERIOD )
  118. return true;
  119. }
  120. return false;
  121. }
  122. //-----------------------------------------------------------------------------
  123. // Purpose:
  124. //-----------------------------------------------------------------------------
  125. class CAchievementTFPlayGameEveryClass : public CTFAchievementFullRound
  126. {
  127. DECLARE_CLASS( CAchievementTFPlayGameEveryClass, CTFAchievementFullRound );
  128. void Init()
  129. {
  130. SetFlags( ACH_SAVE_GLOBAL | ACH_HAS_COMPONENTS | ACH_FILTER_FULL_ROUND_ONLY );
  131. SetGoal( ( TF_LAST_NORMAL_CLASS - 1 ) - TF_FIRST_NORMAL_CLASS + 1 ); //( TF_LAST_NORMAL_CLASS - 1 ) to exclude the new civilian class
  132. BaseClass::Init();
  133. }
  134. virtual void Event_OnRoundComplete( float flRoundTime, IGameEvent *event )
  135. {
  136. float flLastClassChangeTime = m_pAchievementMgr->GetLastClassChangeTime();
  137. if ( flLastClassChangeTime > 0 )
  138. {
  139. // has the player been present and not changed class since the start of this round (minus a grace period)?
  140. if ( flLastClassChangeTime < ( gpGlobals->curtime - flRoundTime ) + TF_FULL_ROUND_GRACE_PERIOD )
  141. {
  142. C_TFPlayer *pTFPlayer = C_TFPlayer::GetLocalTFPlayer();
  143. if ( pTFPlayer )
  144. {
  145. int iClass = pTFPlayer->GetPlayerClass()->GetClassIndex();
  146. if ( iClass >= TF_FIRST_NORMAL_CLASS && iClass <= ( TF_LAST_NORMAL_CLASS - 1 ) ) //( TF_LAST_NORMAL_CLASS - 1 ) to exclude the new civilian class
  147. {
  148. // yes, the achievement is satisfied for this class, set the corresponding bit
  149. int iBitNumber =( iClass - TF_FIRST_NORMAL_CLASS );
  150. EnsureComponentBitSetAndEvaluate( iBitNumber );
  151. }
  152. }
  153. }
  154. }
  155. }
  156. };
  157. DECLARE_ACHIEVEMENT( CAchievementTFPlayGameEveryClass, ACHIEVEMENT_TF_PLAY_GAME_EVERYCLASS, "TF_PLAY_GAME_EVERYCLASS", 5 );
  158. class CAchievementTFPlayGameEveryMap : public CTFAchievementFullRound
  159. {
  160. DECLARE_CLASS( CAchievementTFPlayGameEveryMap, CTFAchievementFullRound );
  161. void Init()
  162. {
  163. SetFlags( ACH_SAVE_GLOBAL | ACH_HAS_COMPONENTS | ACH_FILTER_FULL_ROUND_ONLY );
  164. static const char *szComponents[] =
  165. {
  166. "cp_dustbowl", "cp_granary", "cp_gravelpit", "cp_well", "ctf_2fort", "tc_hydro"
  167. };
  168. m_pszComponentNames = szComponents;
  169. m_iNumComponents = ARRAYSIZE( szComponents );
  170. SetGoal( m_iNumComponents );
  171. }
  172. virtual void ListenForEvents()
  173. {
  174. ListenForGameEvent( "teamplay_round_win" );
  175. }
  176. virtual void Event_OnRoundComplete( float flRoundTime, IGameEvent *event )
  177. {
  178. float flTeamplayStartTime = m_pAchievementMgr->GetTeamplayStartTime();
  179. if ( flTeamplayStartTime > 0 )
  180. {
  181. // has the player been present and on a game team since the start of this round (minus a grace period)?
  182. if ( flTeamplayStartTime < ( gpGlobals->curtime - flRoundTime ) + TF_FULL_ROUND_GRACE_PERIOD )
  183. {
  184. // yes, the achievement is satisfied for this map, set the corresponding bit
  185. OnComponentEvent( m_pAchievementMgr->GetMapName() );
  186. }
  187. }
  188. }
  189. };
  190. DECLARE_ACHIEVEMENT( CAchievementTFPlayGameEveryMap, ACHIEVEMENT_TF_PLAY_GAME_EVERYMAP, "TF_PLAY_GAME_EVERYMAP", 5 );
  191. class CAchievementTFGetHealPoints : public CBaseTFAchievementSimple
  192. {
  193. void Init()
  194. {
  195. SetFlags( ACH_SAVE_GLOBAL );
  196. SetGoal( 25000 );
  197. }
  198. void OnPlayerStatsUpdate()
  199. {
  200. ClassStats_t &classStats = CTFStatPanel::GetClassStats( TF_CLASS_MEDIC );
  201. int iOldCount = m_iCount;
  202. m_iCount = classStats.accumulated.m_iStat[TFSTAT_HEALING];
  203. if ( m_iCount != iOldCount )
  204. {
  205. m_pAchievementMgr->SetDirty( true );
  206. }
  207. if ( IsLocalTFPlayerClass( TF_CLASS_MEDIC ) )
  208. {
  209. EvaluateNewAchievement();
  210. }
  211. }
  212. };
  213. DECLARE_ACHIEVEMENT( CAchievementTFGetHealPoints, ACHIEVEMENT_TF_GET_HEALPOINTS, "TF_GET_HEALPOINTS", 5 );
  214. class CAchievementTFBurnPlayersInMinimumTime : public CBaseTFAchievementSimple
  215. {
  216. void Init()
  217. {
  218. SetFlags( ACH_SAVE_GLOBAL );
  219. SetGoal( 1 );
  220. }
  221. // server awards this achievement, no other code within achievement necessary
  222. };
  223. DECLARE_ACHIEVEMENT( CAchievementTFBurnPlayersInMinimumTime, ACHIEVEMENT_TF_BURN_PLAYERSINMINIMIMTIME, "TF_BURN_PLAYERSINMINIMUMTIME", 5 );
  224. class CAchievementTFGetTurretKills : public CBaseTFAchievementSimple
  225. {
  226. void Init()
  227. {
  228. SetFlags( ACH_SAVE_GLOBAL );
  229. SetGoal( 1 );
  230. }
  231. // server awards this achievement, no other code within achievement necessary
  232. };
  233. DECLARE_ACHIEVEMENT( CAchievementTFGetTurretKills, ACHIEVEMENT_TF_GET_TURRETKILLS, "TF_GET_TURRETKILLS", 5 );
  234. class CAchievementTFGetHeadshots: public CBaseTFAchievementSimple
  235. {
  236. void Init()
  237. {
  238. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
  239. SetGoal( 25 );
  240. }
  241. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  242. {
  243. // was this a headshot by this player?
  244. if ( ( pAttacker == C_TFPlayer::GetLocalTFPlayer() ) && ( IsHeadshot(event->GetInt( "customkill" ) ) ) )
  245. {
  246. // Increment count. Count will also get slammed whenever we get a stats update from server. They should generally agree,
  247. // but server is authoritative.
  248. IncrementCount();
  249. }
  250. }
  251. void OnPlayerStatsUpdate()
  252. {
  253. // when stats are updated by server, use most recent stat value
  254. ClassStats_t &classStats = CTFStatPanel::GetClassStats( TF_CLASS_SNIPER );
  255. int iOldCount = m_iCount;
  256. m_iCount = classStats.accumulated.m_iStat[TFSTAT_HEADSHOTS];
  257. if ( m_iCount != iOldCount )
  258. {
  259. m_pAchievementMgr->SetDirty( true );
  260. }
  261. if ( IsLocalTFPlayerClass( TF_CLASS_SNIPER ) )
  262. {
  263. EvaluateNewAchievement();
  264. }
  265. }
  266. };
  267. DECLARE_ACHIEVEMENT( CAchievementTFGetHeadshots, ACHIEVEMENT_TF_GET_HEADSHOTS, "TF_GET_HEADSHOTS", 5 );
  268. class CAchievementTFKillNemesis : public CBaseTFAchievementSimple
  269. {
  270. void Init()
  271. {
  272. SetFlags( ACH_LISTEN_KILL_EVENTS | ACH_SAVE_GLOBAL );
  273. SetGoal( 5 );
  274. }
  275. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  276. {
  277. if ( ( ( event->GetInt( "death_flags" ) & TF_DEATH_REVENGE ) ) && ( pAttacker == C_TFPlayer::GetLocalTFPlayer() ) )
  278. {
  279. // local player got revenge as primary killer
  280. IncrementCount();
  281. }
  282. else if ( event->GetInt( "death_flags" ) & TF_DEATH_ASSISTER_REVENGE )
  283. {
  284. int iAssisterIndex = engine->GetPlayerForUserID( event->GetInt( "assister" ) );
  285. if ( iAssisterIndex > 0 )
  286. {
  287. CBaseEntity *pAssister = UTIL_PlayerByIndex( iAssisterIndex );
  288. if ( pAssister && ( pAssister == C_TFPlayer::GetLocalTFPlayer() ) )
  289. {
  290. // local player got revenge as assister
  291. IncrementCount();
  292. }
  293. }
  294. }
  295. }
  296. };
  297. DECLARE_ACHIEVEMENT( CAchievementTFKillNemesis, ACHIEVEMENT_TF_KILL_NEMESIS, "TF_KILL_NEMESIS", 5 );
  298. class CAchievementTFGetConsecutiveKillsNoDeaths : public CBaseTFAchievementSimple
  299. {
  300. void Init()
  301. {
  302. SetFlags( ACH_LISTEN_KILL_EVENTS | ACH_SAVE_GLOBAL );
  303. SetGoal( 1 );
  304. m_iConsecutiveKills = 0;
  305. }
  306. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  307. {
  308. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  309. if ( pLocalPlayer == pVictim )
  310. {
  311. m_iConsecutiveKills = 0;
  312. }
  313. else if ( pLocalPlayer == pAttacker )
  314. {
  315. m_iConsecutiveKills++;
  316. if ( 5 == m_iConsecutiveKills )
  317. {
  318. IncrementCount();
  319. }
  320. }
  321. }
  322. int m_iConsecutiveKills;
  323. };
  324. DECLARE_ACHIEVEMENT( CAchievementTFGetConsecutiveKillsNoDeaths, ACHIEVEMENT_TF_GET_CONSECUTIVEKILLS_NODEATHS, "TF_GET_CONSECUTIVEKILLS_NODEATHS", 10 );
  325. class CAchievementTFGetHealedByEnemy: public CBaseTFAchievementSimple
  326. {
  327. void Init()
  328. {
  329. SetFlags( ACH_SAVE_GLOBAL );
  330. SetGoal( 1 );
  331. }
  332. // server awards this achievement, no other code within achievement necessary
  333. };
  334. DECLARE_ACHIEVEMENT( CAchievementTFGetHealedByEnemy, ACHIEVEMENT_TF_GET_HEALED_BYENEMY, "TF_GET_HEALED_BYENEMY", 15 );
  335. class CAchievementTFPlayGameFriendsOnly : public CBaseTFAchievementSimple
  336. {
  337. void Init()
  338. {
  339. SetFlags( ACH_SAVE_GLOBAL | ACH_FILTER_FULL_ROUND_ONLY );
  340. SetGoal( 1 );
  341. }
  342. virtual void ListenForEvents()
  343. {
  344. ListenForGameEvent( "teamplay_round_win" );
  345. }
  346. void FireGameEvent_Internal( IGameEvent *event )
  347. {
  348. if ( 0 == Q_strcmp( event->GetName(), "teamplay_round_win" ) )
  349. {
  350. // Are there at least 7 friends in the game? (at least 8 players total)
  351. if ( CalcPlayersOnFriendsList( 7 ) )
  352. {
  353. IncrementCount();
  354. }
  355. }
  356. }
  357. };
  358. DECLARE_ACHIEVEMENT( CAchievementTFPlayGameFriendsOnly, ACHIEVEMENT_TF_PLAY_GAME_FRIENDSONLY, "TF_PLAY_GAME_FRIENDSONLY", 10 );
  359. class CAchievementTFWinMultipleGames : public CTFAchievementFullRound
  360. {
  361. DECLARE_CLASS( CAchievementTFWinMultipleGames, CTFAchievementFullRound );
  362. void Init()
  363. {
  364. SetFlags( ACH_SAVE_GLOBAL | ACH_FILTER_FULL_ROUND_ONLY );
  365. SetGoal( 20 );
  366. BaseClass::Init();
  367. }
  368. virtual void Event_OnRoundComplete( float flRoundTime, IGameEvent *event )
  369. {
  370. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  371. if ( pLocalPlayer )
  372. {
  373. // was the player on the winning team?
  374. int iPlayerTeam = pLocalPlayer->GetTeamNumber();
  375. int iWinningTeam = event->GetInt( "team" );
  376. if ( ( iWinningTeam >= FIRST_GAME_TEAM ) && ( iPlayerTeam == iWinningTeam ) )
  377. {
  378. IncrementCount();
  379. }
  380. }
  381. }
  382. };
  383. DECLARE_ACHIEVEMENT( CAchievementTFWinMultipleGames, ACHIEVEMENT_TF_WIN_MULTIPLEGAMES, "TF_WIN_MULTIPLEGAMES", 10 );
  384. class CAchievementTFGetMultipleKills : public CBaseTFAchievementSimple
  385. {
  386. void Init()
  387. {
  388. // listen for player kill enemy events, base class will increment count each time that happens
  389. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
  390. SetGoal( 1000 );
  391. }
  392. void OnPlayerStatsUpdate()
  393. {
  394. // when stats are updated by server, use most recent stat values
  395. int iKills = 0;
  396. // get sum of kills per class across all classes to get total kills
  397. for ( int iClass = TF_FIRST_NORMAL_CLASS; iClass <= ( TF_LAST_NORMAL_CLASS - 1 ); iClass++ ) //( TF_LAST_NORMAL_CLASS - 1 ) to exclude the new civilian class
  398. {
  399. ClassStats_t &classStats = CTFStatPanel::GetClassStats( iClass );
  400. iKills += classStats.accumulated.m_iStat[TFSTAT_KILLS];
  401. }
  402. int iOldCount = m_iCount;
  403. m_iCount = iKills;
  404. if ( m_iCount != iOldCount )
  405. {
  406. m_pAchievementMgr->SetDirty( true );
  407. }
  408. EvaluateNewAchievement();
  409. }
  410. };
  411. DECLARE_ACHIEVEMENT( CAchievementTFGetMultipleKills, ACHIEVEMENT_TF_GET_MULTIPLEKILLS, "TF_GET_MULTIPLEKILLS", 15 );
  412. class CAchievementTFWin2FortNoEnemyCaps : public CBaseTFAchievementSimple
  413. {
  414. void Init()
  415. {
  416. SetFlags( ACH_SAVE_GLOBAL );
  417. SetGoal( 1 );
  418. SetMapNameFilter( "ctf_2fort" );
  419. }
  420. virtual void ListenForEvents()
  421. {
  422. ListenForGameEvent( "teamplay_round_win" );
  423. }
  424. void FireGameEvent_Internal( IGameEvent *event )
  425. {
  426. if ( 0 == Q_strcmp( event->GetName(), "teamplay_round_win" ) )
  427. {
  428. if ( event->GetBool( "was_sudden_death" ) == false )
  429. {
  430. if ( event->GetInt( "team" ) == GetLocalPlayerTeam() )
  431. {
  432. // did the enemy team get any flag captures?
  433. C_TFTeam *pEnemyTeam = GetGlobalTFTeam( TF_TEAM_BLUE + TF_TEAM_RED - GetLocalPlayerTeam() );
  434. if ( 0 == pEnemyTeam->GetFlagCaptures() )
  435. {
  436. IncrementCount();
  437. }
  438. }
  439. }
  440. }
  441. }
  442. };
  443. DECLARE_ACHIEVEMENT( CAchievementTFWin2FortNoEnemyCaps, ACHIEVEMENT_TF_WIN_2FORT_NOENEMYCAPS, "TF_WIN_2FORT_NOENEMYCAPS", 5 );
  444. class CAchievementTFWinWellMinimumTime : public CBaseTFAchievementSimple
  445. {
  446. void Init()
  447. {
  448. SetFlags( ACH_SAVE_GLOBAL );
  449. SetGoal( 1 );
  450. SetMapNameFilter( "cp_well" );
  451. }
  452. virtual void ListenForEvents()
  453. {
  454. ListenForGameEvent( "teamplay_round_win" );
  455. }
  456. void FireGameEvent_Internal( IGameEvent *event )
  457. {
  458. if ( 0 == Q_strcmp( event->GetName(), "teamplay_round_win" ) )
  459. {
  460. if ( event->GetInt( "team" ) == GetLocalPlayerTeam() )
  461. {
  462. float flRoundTime = event->GetFloat( "round_time", 0 );
  463. if ( flRoundTime > 0 && flRoundTime < 5 * 60 )
  464. {
  465. IncrementCount();
  466. }
  467. }
  468. }
  469. }
  470. };
  471. DECLARE_ACHIEVEMENT( CAchievementTFWinWellMinimumTime, ACHIEVEMENT_TF_WIN_WELL_MINIMUMTIME, "TF_WIN_WELL_MINIMUMTIME", 10 );
  472. class CAchievementTFWinHydroNoEnemyCaps : public CBaseTFAchievementSimple
  473. {
  474. void Init()
  475. {
  476. SetFlags( ACH_SAVE_GLOBAL | ACH_FILTER_FULL_ROUND_ONLY );
  477. SetGoal( 1 );
  478. SetMapNameFilter( "tc_hydro" );
  479. }
  480. virtual void ListenForEvents()
  481. {
  482. ListenForGameEvent( "teamplay_round_win" );
  483. }
  484. void FireGameEvent_Internal( IGameEvent *event )
  485. {
  486. // winning hydro with no enemy caps means there were 2 previous minirounds completed (3 total for a shutout)
  487. // and local player's team won the final round
  488. if ( ( 2 == m_pAchievementMgr->GetMiniroundsCompleted() ) && ( CheckWinNoEnemyCaps( event, TEAM_ROLE_NONE ) ) )
  489. {
  490. IncrementCount();
  491. }
  492. }
  493. };
  494. DECLARE_ACHIEVEMENT( CAchievementTFWinHydroNoEnemyCaps, ACHIEVEMENT_TF_WIN_HYDRO_NOENEMYCAPS, "TF_WIN_HYDRO_NOENEMYCAPS", 20 );
  495. class CAchievementTFWinDustbowlNoEnemyCaps : public CBaseTFAchievementSimple
  496. {
  497. void Init()
  498. {
  499. SetFlags( ACH_SAVE_GLOBAL | ACH_FILTER_FULL_ROUND_ONLY );
  500. SetGoal( 1 );
  501. SetMapNameFilter( "cp_dustbowl" );
  502. }
  503. virtual void ListenForEvents()
  504. {
  505. ListenForGameEvent( "teamplay_round_win" );
  506. }
  507. void FireGameEvent_Internal( IGameEvent *event )
  508. {
  509. // defending dustbowl with no enemy caps means there were no previous minirounds completed (that would be an attacker capture),
  510. // the player was on the defending team and they won with no enemy caps
  511. if ( ( 0 == m_pAchievementMgr->GetMiniroundsCompleted() ) && CheckWinNoEnemyCaps( event, TEAM_ROLE_DEFENDERS ) )
  512. {
  513. IncrementCount();
  514. }
  515. }
  516. };
  517. DECLARE_ACHIEVEMENT( CAchievementTFWinDustbowlNoEnemyCaps, ACHIEVEMENT_TF_WIN_DUSTBOWL_NOENEMYCAPS, "TF_WIN_DUSTBOWL_NOENEMYCAPS", 10 );
  518. class CAchievementTFWinGravelPitNoEnemyCaps : public CBaseTFAchievementSimple
  519. {
  520. void Init()
  521. {
  522. SetFlags( ACH_SAVE_GLOBAL );
  523. SetGoal( 1 );
  524. SetMapNameFilter( "cp_gravelpit" );
  525. }
  526. virtual void ListenForEvents()
  527. {
  528. ListenForGameEvent( "teamplay_round_win" );
  529. }
  530. void FireGameEvent_Internal( IGameEvent *event )
  531. {
  532. // Was player on defenders and won with no enemy caps?
  533. if ( CheckWinNoEnemyCaps( event, TEAM_ROLE_DEFENDERS ) )
  534. {
  535. IncrementCount();
  536. }
  537. }
  538. };
  539. DECLARE_ACHIEVEMENT( CAchievementTFWinGravelPitNoEnemyCaps, ACHIEVEMENT_TF_WIN_GRAVELPIT_NOENEMYCAPS, "TF_WIN_GRAVELPIT_NOENEMYCAPS", 30 );
  540. class CAchievementTFKillEnemiesAfterTeleporting : public CTFAchievementTeleporterTimingKills<CBaseAchievement>
  541. {
  542. // stub -- all code in parent class
  543. };
  544. DECLARE_ACHIEVEMENT( CAchievementTFKillEnemiesAfterTeleporting, ACHIEVEMENT_TF_GENERAL_KILL_ENEMIES_AFTER_TELEPORTING, "TF_GENERAL_KILL_ENEMIES_AFTER_TELEPORTING", 10 );
  545. //-----------------------------------------------------------------------------
  546. // Purpose: see if a round win was a win for the local player with no enemy caps
  547. //-----------------------------------------------------------------------------
  548. bool CheckWinNoEnemyCaps( IGameEvent *event, int iRole )
  549. {
  550. if ( 0 == Q_strcmp( event->GetName(), "teamplay_round_win" ) )
  551. {
  552. if ( event->GetInt( "team" ) == GetLocalPlayerTeam() )
  553. {
  554. int iLosingTeamCaps = event->GetInt( "losing_team_num_caps" );
  555. if ( 0 == iLosingTeamCaps )
  556. {
  557. C_TFTeam *pLocalTeam = GetGlobalTFTeam( GetLocalPlayerTeam() );
  558. if ( pLocalTeam )
  559. {
  560. int iRolePlayer = pLocalTeam->GetRole();
  561. if ( iRole > TEAM_ROLE_NONE && ( iRolePlayer != iRole ) )
  562. return false;
  563. return true;
  564. }
  565. }
  566. }
  567. }
  568. return false;
  569. }
  570. //-----------------------------------------------------------------------------
  571. // Purpose: Helper function to determine if local player is specified class
  572. //-----------------------------------------------------------------------------
  573. bool IsLocalTFPlayerClass( int iClass )
  574. {
  575. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  576. return( pLocalPlayer && pLocalPlayer->IsPlayerClass( iClass ) );
  577. }
  578. //-----------------------------------------------------------------------------
  579. // Purpose: Query if the gamerules allows achievement progress at this time
  580. //-----------------------------------------------------------------------------
  581. bool GameRulesAllowsAchievements( void )
  582. {
  583. bool bRetVal = false;
  584. if ( ( TFGameRules()->State_Get() < GR_STATE_TEAM_WIN ) ||
  585. ( TFGameRules()->State_Get() == GR_STATE_STALEMATE ) )
  586. {
  587. bRetVal = true;
  588. }
  589. return bRetVal;
  590. }
  591. //----------------------------------------------------------------------------------------------------------------
  592. // Receive the PlayerIgnitedInv user message and send out a clientside event for achievements to hook.
  593. void __MsgFunc_PlayerIgnitedInv( bf_read &msg )
  594. {
  595. int iPyroEntIndex = (int) msg.ReadByte();
  596. int iVictimEntIndex = (int) msg.ReadByte();
  597. int iMedicEntIndex = (int) msg.ReadByte();
  598. IGameEvent *event = gameeventmanager->CreateEvent( "player_ignited_inv" );
  599. if ( event )
  600. {
  601. event->SetInt( "pyro_entindex", iPyroEntIndex );
  602. event->SetInt( "victim_entindex", iVictimEntIndex );
  603. event->SetInt( "medic_entindex", iMedicEntIndex );
  604. gameeventmanager->FireEventClientSide( event );
  605. }
  606. }
  607. // Receive the PlayerIgnited user message and send out a clientside event for achievements to hook.
  608. void __MsgFunc_PlayerIgnited( bf_read &msg )
  609. {
  610. int iPyroEntIndex = (int) msg.ReadByte();
  611. int iVictimEntIndex = (int) msg.ReadByte();
  612. int iWeaponID = (int) msg.ReadByte();
  613. IGameEvent *event = gameeventmanager->CreateEvent( "player_ignited" );
  614. if ( event )
  615. {
  616. event->SetInt( "pyro_entindex", iPyroEntIndex );
  617. event->SetInt( "victim_entindex", iVictimEntIndex );
  618. event->SetInt( "weaponid", iWeaponID );
  619. gameeventmanager->FireEventClientSide( event );
  620. }
  621. }
  622. // Receive the Damage user message and send out a clientside event for achievements to hook.
  623. void __MsgFunc_Damage( bf_read &msg )
  624. {
  625. int iDamage = msg.ReadShort();
  626. int iDmgBits = msg.ReadLong();
  627. IGameEvent *event = gameeventmanager->CreateEvent( "player_damaged" );
  628. if ( event )
  629. {
  630. event->SetInt( "amount", iDamage );
  631. event->SetInt( "type", iDmgBits );
  632. gameeventmanager->FireEventClientSide( event );
  633. }
  634. // NVNT START implementing rest of message for damage directions
  635. if(iDamage == 0)
  636. return; // no damage forces for no damage.
  637. // get the local player.
  638. C_TFPlayer *pLocal = C_TFPlayer::GetLocalTFPlayer();
  639. if(!pLocal)
  640. return;// if we dont have a local player ignore this message.
  641. Vector attackerPosition(0,0,0);
  642. if(msg.ReadOneBit())
  643. {
  644. // if we read one bit then that means we have shooters origin.
  645. msg.ReadBitVec3Coord( attackerPosition );
  646. }else{
  647. // if it is non origin, just set the origin below the player
  648. attackerPosition = pLocal->GetAbsOrigin() + Vector(0,0,-10);
  649. }
  650. // get the direction in world
  651. Vector attackDirectionLocal(vec3_origin);
  652. // rotate the direction to the local players view
  653. pLocal->WorldToEntitySpace(attackerPosition, &attackDirectionLocal);
  654. if ( haptics )
  655. {
  656. Vector hapticSpace( attackDirectionLocal.y, -attackDirectionLocal.z, attackDirectionLocal.x );
  657. hapticSpace.NormalizeInPlace();
  658. haptics->ApplyDamageEffect((float)iDamage, iDmgBits, hapticSpace);
  659. }
  660. // NVNT END
  661. }
  662. // Receive the UpdateAchievement user message and send out a clientside event for achievements to hook.
  663. void __MsgFunc_UpdateAchievement( bf_read &msg )
  664. {
  665. int iIndex = (int) msg.ReadShort();
  666. int nData = (int) msg.ReadShort();
  667. g_AchievementMgrTF.UpdateAchievement( iIndex, nData );
  668. }
  669. // Receive the PlayerJarated user message and send out a clientside event for achievements to hook.
  670. void __MsgFunc_PlayerJarated( bf_read &msg )
  671. {
  672. int iThrowerEntIndex = (int) msg.ReadByte();
  673. int iVictimEntIndex = (int) msg.ReadByte();
  674. IGameEvent *event = gameeventmanager->CreateEvent( "player_jarated" );
  675. if ( event )
  676. {
  677. event->SetInt( "thrower_entindex", iThrowerEntIndex );
  678. event->SetInt( "victim_entindex", iVictimEntIndex );
  679. gameeventmanager->FireEventClientSide( event );
  680. }
  681. }
  682. void __MsgFunc_PlayerJaratedFade( bf_read &msg )
  683. {
  684. int iThrowerEntIndex = (int) msg.ReadByte();
  685. int iVictimEntIndex = (int) msg.ReadByte();
  686. IGameEvent *event = gameeventmanager->CreateEvent( "player_jarated_fade" );
  687. if ( event )
  688. {
  689. event->SetInt( "thrower_entindex", iThrowerEntIndex );
  690. event->SetInt( "victim_entindex", iVictimEntIndex );
  691. gameeventmanager->FireEventClientSide( event );
  692. }
  693. }
  694. //This is so dumb.
  695. void __MsgFunc_PlayerShieldBlocked( bf_read &msg )
  696. {
  697. int iAttacker = (int) msg.ReadByte();
  698. int iBlocker = (int) msg.ReadByte();
  699. IGameEvent *event = gameeventmanager->CreateEvent( "player_shield_blocked" );
  700. if ( event )
  701. {
  702. event->SetInt( "attacker_entindex", iAttacker );
  703. event->SetInt( "blocker_entindex", iBlocker );
  704. gameeventmanager->FireEventClientSide( event );
  705. }
  706. }
  707. // Receive the PlayerExtinguished user message and send out a clientside event for achievements to hook.
  708. void __MsgFunc_PlayerExtinguished( bf_read &msg )
  709. {
  710. int iMedicEntIndex = (int) msg.ReadByte();
  711. int iVictimEntIndex = (int) msg.ReadByte();
  712. IGameEvent *event = gameeventmanager->CreateEvent( "player_extinguished" );
  713. if ( event )
  714. {
  715. event->SetInt( "victim", iVictimEntIndex );
  716. event->SetInt( "healer", iMedicEntIndex );
  717. gameeventmanager->FireEventClientSide( event );
  718. }
  719. }
  720. void CAchievementTopScoreboard::Init()
  721. {
  722. SetFlags( ACH_SAVE_GLOBAL | ACH_FILTER_FULL_ROUND_ONLY );
  723. SetGoal(1);
  724. }
  725. void CAchievementTopScoreboard::ListenForEvents()
  726. {
  727. BaseClass::ListenForEvents();
  728. ListenForGameEvent( "teamplay_round_active" );
  729. }
  730. void CAchievementTopScoreboard::Event_OnRoundComplete( float flRoundTime, IGameEvent *event )
  731. {
  732. if ( PlayerWasInEntireRound( flRoundTime ) )
  733. {
  734. int iLocalTeam = C_TFPlayer::GetLocalTFPlayer()->GetTeamNumber();
  735. if ( GetGlobalTFTeam(iLocalTeam) && GetGlobalTFTeam(iLocalTeam)->GetNumPlayers() >= 6 )
  736. {
  737. if ( g_TF_PR )
  738. {
  739. bool bHighest = true;
  740. int iLocalScore = g_TF_PR->GetTotalScore( C_TFPlayer::GetLocalTFPlayer()->entindex() );
  741. // See if the player's on the top of the scoreboard
  742. for( int playerIndex = 1; playerIndex <= MAX_PLAYERS; playerIndex++ )
  743. {
  744. if ( !g_PR->IsConnected( playerIndex ) || g_PR->IsLocalPlayer( playerIndex ) )
  745. continue;
  746. if ( g_PR->GetTeam(playerIndex) != iLocalTeam )
  747. continue;
  748. if ( g_TF_PR->GetTotalScore(playerIndex) > iLocalScore )
  749. {
  750. bHighest = false;
  751. break;
  752. }
  753. }
  754. if ( bHighest )
  755. {
  756. IncrementCount();
  757. }
  758. }
  759. }
  760. }
  761. }
  762. //-----------------------------------------------------------------------------
  763. // Purpose:
  764. //-----------------------------------------------------------------------------
  765. extern int Training_GetNumCourses();
  766. extern int Training_GetProgressCount();
  767. class CAchievementTFCompleteTraining : public CBaseTFAchievementSimple
  768. {
  769. DECLARE_CLASS( CAchievementTFCompleteTraining, CBaseAchievement );
  770. void Init()
  771. {
  772. SetFlags( ACH_SAVE_GLOBAL | ACH_HAS_COMPONENTS );
  773. SetGoal( Training_GetNumCourses() );
  774. SetStoreProgressInSteam( true );
  775. SetCount( Training_GetProgressCount() );
  776. BaseClass::Init();
  777. }
  778. virtual void UpdateAchievement( int nData )
  779. {
  780. SetCount( nData );
  781. EvaluateNewAchievement();
  782. }
  783. };
  784. DECLARE_ACHIEVEMENT( CAchievementTFCompleteTraining, ACHIEVEMENT_TF_COMPLETE_TRAINING, "TF_COMPLETE_TRAINING", 5 );
  785. //----------------------------------------------------------------------------------------------------------------
  786. class CAchievementTF_FireWaterJump : public CBaseTFAchievement
  787. {
  788. void Init()
  789. {
  790. SetFlags( ACH_SAVE_GLOBAL );
  791. SetGoal( 1 );
  792. }
  793. // server awards this achievement, no other code within achievement necessary
  794. };
  795. DECLARE_ACHIEVEMENT( CAchievementTF_FireWaterJump, ACHIEVEMENT_TF_FIRE_WATERJUMP, "TF_FIRE_WATERJUMP", 5 );
  796. //----------------------------------------------------------------------------------------------------------------
  797. class CAchievementTFChristmasCollectGifts : public CBaseTFAchievementSimple
  798. {
  799. void Init()
  800. {
  801. SetFlags( ACH_SAVE_GLOBAL );
  802. SetGoal( 3 );
  803. SetStoreProgressInSteam( true );
  804. }
  805. virtual void ListenForEvents()
  806. {
  807. ListenForGameEvent( "christmas_gift_grab" );
  808. }
  809. void FireGameEvent_Internal( IGameEvent *event )
  810. {
  811. if ( !TFGameRules()->IsHolidayActive( kHoliday_Christmas ) )
  812. return;
  813. if ( Q_strcmp( event->GetName(), "christmas_gift_grab" ) == 0 )
  814. {
  815. int iPlayer = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
  816. CBaseEntity *pPlayer = UTIL_PlayerByIndex( iPlayer );
  817. if ( pPlayer && pPlayer == C_TFPlayer::GetLocalTFPlayer() )
  818. {
  819. IncrementCount();
  820. }
  821. }
  822. }
  823. };
  824. DECLARE_ACHIEVEMENT( CAchievementTFChristmasCollectGifts, ACHIEVEMENT_TF_CHRISTMAS_COLLECT_GIFTS, "TF_CHRISTMAS_COLLECT_GIFTS", 5 );
  825. //----------------------------------------------------------------------------------------------------------------
  826. class CAchievementTF_KillBalloonicornOwners : public CBaseTFAchievement
  827. {
  828. void Init()
  829. {
  830. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
  831. SetGoal( 79 );
  832. SetStoreProgressInSteam( true );
  833. }
  834. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  835. {
  836. CSchemaItemDefHandle pItemDef_Balloonicorn( "Pet Balloonicorn" );
  837. CSchemaItemDefHandle pItemDef_BalloonicornPromo( "Pet Balloonicorn Promo" );
  838. CSchemaItemDefHandle pItemDef_BalloonicornPlushPromo( "Pet Balloonicorn Plush Promo" );
  839. CSchemaItemDefHandle pItemDef_Reindoonicorn( "Pet Reindoonicorn" );
  840. C_TFPlayer *pLocalPlayer = ToTFPlayer( C_BasePlayer::GetLocalPlayer() );
  841. if ( pLocalPlayer )
  842. {
  843. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  844. if ( pTFVictim && ( pAttacker == pLocalPlayer ) && ( pTFVictim->GetTeamNumber() != pLocalPlayer->GetTeamNumber() ) )
  845. {
  846. int nVisionOptInFlags = 0;
  847. CALL_ATTRIB_HOOK_INT_ON_OTHER( pLocalPlayer, nVisionOptInFlags, vision_opt_in_flags );
  848. // Does the local player have PyroVision on?
  849. if ( nVisionOptInFlags & TF_VISION_FILTER_PYRO )
  850. {
  851. // Is the victim wearing the Balloonicorn?
  852. for ( int i = 0 ; i < pTFVictim->GetNumWearables() ; ++i )
  853. {
  854. C_EconWearable *pWearable = pTFVictim->GetWearable( i );
  855. if ( pWearable && pWearable->GetAttributeContainer() )
  856. {
  857. CEconItemView *pItem = pWearable->GetAttributeContainer()->GetItem();
  858. if ( pItem && pItem->IsValid() )
  859. {
  860. if ( pItem->GetItemDefinition() == pItemDef_Balloonicorn ||
  861. pItem->GetItemDefinition() == pItemDef_BalloonicornPromo ||
  862. pItem->GetItemDefinition() == pItemDef_BalloonicornPlushPromo ||
  863. pItem->GetItemDefinition() == pItemDef_Reindoonicorn )
  864. {
  865. IncrementCount();
  866. }
  867. }
  868. }
  869. }
  870. }
  871. }
  872. }
  873. }
  874. };
  875. DECLARE_ACHIEVEMENT( CAchievementTF_KillBalloonicornOwners, ACHIEVEMENT_TF_KILL_BALLOONICORN_OWNERS, "TF_KILL_BALLOONICORN_OWNERS", 5 );
  876. //----------------------------------------------------------------------------------------------------------------
  877. class CAchievementTF_MultipleBFF : public CBaseTFAchievement
  878. {
  879. void Init()
  880. {
  881. SetFlags( ACH_LISTEN_KILL_EVENTS | ACH_SAVE_GLOBAL );
  882. SetGoal( 1 );
  883. }
  884. virtual void ListenForEvents( void )
  885. {
  886. ListenForGameEvent( "remove_nemesis_relationships" );
  887. // clear data on level init
  888. m_hBFFs.Purge();
  889. }
  890. void FireGameEvent_Internal( IGameEvent *event )
  891. {
  892. if ( FStrEq( event->GetName(), "remove_nemesis_relationships" ) )
  893. {
  894. int iPlayerIndex = event->GetInt( "player" );
  895. if ( iPlayerIndex == GetLocalPlayerIndex() )
  896. {
  897. // this is the local player, clear our list
  898. m_hBFFs.Purge();
  899. }
  900. else
  901. {
  902. // is this player in our list?
  903. CTFPlayer *pPlayer = ToTFPlayer( UTIL_PlayerByIndex( iPlayerIndex ) );
  904. int index = m_hBFFs.Find( pPlayer );
  905. if ( index != m_hBFFs.InvalidIndex() )
  906. {
  907. m_hBFFs.Remove( index );
  908. }
  909. }
  910. }
  911. }
  912. void ValidateList( void )
  913. {
  914. // remove anyone on the local player's team to clean up changing teams, getting
  915. // team balanced, etc., if they're still on the other team, we're fine.
  916. for ( int i = m_hBFFs.Count() - 1 ; i >= 0 ; i-- )
  917. {
  918. C_TFPlayer *pPlayer = m_hBFFs[i];
  919. if ( pPlayer->GetTeamNumber() == GetLocalPlayerTeam() )
  920. {
  921. m_hBFFs.Remove( i );
  922. }
  923. }
  924. }
  925. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  926. {
  927. C_TFPlayer *pLocalPlayer = ToTFPlayer( C_BasePlayer::GetLocalPlayer() );
  928. if ( pLocalPlayer )
  929. {
  930. CTFPlayer *pTFAttacker = ToTFPlayer( pAttacker );
  931. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  932. int iDeathFlags = event->GetInt( "death_flags" );
  933. bool bDomination = ( iDeathFlags & TF_DEATH_DOMINATION ) || ( iDeathFlags & TF_DEATH_ASSISTER_DOMINATION );
  934. bool bRevenge = ( iDeathFlags & TF_DEATH_REVENGE ) || ( iDeathFlags & TF_DEATH_ASSISTER_REVENGE );
  935. if ( pTFVictim && ( pTFAttacker == pLocalPlayer ) && bDomination )
  936. {
  937. ValidateList();
  938. int nVisionOptInFlags = 0;
  939. CALL_ATTRIB_HOOK_INT_ON_OTHER( pLocalPlayer, nVisionOptInFlags, vision_opt_in_flags );
  940. if ( nVisionOptInFlags & TF_VISION_FILTER_PYRO )
  941. {
  942. int index = m_hBFFs.Find( pTFVictim );
  943. if ( index == m_hBFFs.InvalidIndex() )
  944. {
  945. m_hBFFs.AddToHead( pTFVictim );
  946. }
  947. if ( m_hBFFs.Count() >= 2 )
  948. {
  949. IncrementCount();
  950. }
  951. }
  952. }
  953. else if ( pTFAttacker && ( pTFVictim == pLocalPlayer ) && bRevenge )
  954. {
  955. ValidateList();
  956. int index = m_hBFFs.Find( pTFAttacker );
  957. if ( index != m_hBFFs.InvalidIndex() )
  958. {
  959. m_hBFFs.Remove( index );
  960. }
  961. }
  962. }
  963. }
  964. private:
  965. CUtlVector< CHandle<C_TFPlayer> > m_hBFFs;
  966. };
  967. DECLARE_ACHIEVEMENT( CAchievementTF_MultipleBFF, ACHIEVEMENT_TF_MULTIPLE_BFF, "TF_MULTIPLE_BFF", 5 );
  968. //----------------------------------------------------------------------------------------------------------------
  969. class CAchievementTF_TeamPyrovision : public CBaseTFAchievement
  970. {
  971. void Init()
  972. {
  973. SetFlags( ACH_SAVE_GLOBAL );
  974. SetGoal( 1 );
  975. SetNextThink( 1.0 );
  976. }
  977. virtual void Think( void )
  978. {
  979. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  980. if ( pLocalPlayer && ( pLocalPlayer->GetTeamNumber() >= FIRST_GAME_TEAM ) )
  981. {
  982. int nVisionOptInFlags = 0;
  983. CALL_ATTRIB_HOOK_INT_ON_OTHER( pLocalPlayer, nVisionOptInFlags, vision_opt_in_flags );
  984. if ( nVisionOptInFlags & TF_VISION_FILTER_PYRO )
  985. {
  986. int nCount = 0;
  987. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  988. {
  989. C_BasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  990. if ( !pPlayer )
  991. continue;
  992. if ( pPlayer == pLocalPlayer )
  993. {
  994. nCount++;
  995. }
  996. else if ( pPlayer->GetTeamNumber() == pLocalPlayer->GetTeamNumber() )
  997. {
  998. int nTempFlags = 0;
  999. CALL_ATTRIB_HOOK_INT_ON_OTHER( pPlayer, nTempFlags, vision_opt_in_flags );
  1000. if ( nTempFlags & TF_VISION_FILTER_PYRO )
  1001. {
  1002. nCount++;
  1003. }
  1004. }
  1005. }
  1006. if ( nCount >= 6 )
  1007. {
  1008. IncrementCount();
  1009. ClearThink();
  1010. return;
  1011. }
  1012. }
  1013. }
  1014. SetNextThink( 1.0 );
  1015. }
  1016. };
  1017. DECLARE_ACHIEVEMENT( CAchievementTF_TeamPyrovision, ACHIEVEMENT_TF_TEAM_PYROVISION, "TF_TEAM_PYROVISION", 5 );
  1018. //----------------------------------------------------------------------------------------------------------------
  1019. class CAchievementTF_DominateForGoggles : public CBaseTFAchievement
  1020. {
  1021. void Init()
  1022. {
  1023. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
  1024. SetGoal( 1 );
  1025. }
  1026. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1027. {
  1028. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  1029. bool bDomination = event->GetInt( "death_flags" ) & TF_DEATH_DOMINATION;
  1030. if ( pTFVictim && ( pAttacker == C_TFPlayer::GetLocalTFPlayer() ) && ( bDomination == true ) )
  1031. {
  1032. // are they wearing the PyroVision goggles?
  1033. for ( int i = 0 ; i < pTFVictim->GetNumWearables() ; ++i )
  1034. {
  1035. C_EconWearable *pWearable = pTFVictim->GetWearable( i );
  1036. if ( pWearable && pWearable->GetAttributeContainer() )
  1037. {
  1038. CEconItemView *pItem = pWearable->GetAttributeContainer()->GetItem();
  1039. if ( pItem && pItem->IsValid() )
  1040. {
  1041. if ( ( pItem->GetItemDefIndex() == 743 ) || // Autogrant PyroVision Goggles
  1042. ( pItem->GetItemDefIndex() == 744 ) ) // PyroVision Goggles
  1043. {
  1044. IncrementCount();
  1045. }
  1046. }
  1047. }
  1048. }
  1049. }
  1050. }
  1051. };
  1052. DECLARE_ACHIEVEMENT( CAchievementTF_DominateForGoggles, ACHIEVEMENT_TF_DOMINATE_FOR_GOGGLES, "TF_DOMINATE_FOR_GOGGLES", 5 );
  1053. //----------------------------------------------------------------------------------------------------------------
  1054. class CAchievementTF_ParachuteKillGrind : public CBaseTFAchievement
  1055. {
  1056. public:
  1057. void Init()
  1058. {
  1059. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
  1060. SetGoal( 10 );
  1061. SetStoreProgressInSteam( true );
  1062. }
  1063. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1064. {
  1065. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  1066. if ( pTFVictim && ( pAttacker == C_TFPlayer::GetLocalTFPlayer() ) )
  1067. {
  1068. if ( pTFVictim->m_Shared.InCond( TF_COND_PARACHUTE_DEPLOYED ) )
  1069. {
  1070. IncrementCount();
  1071. }
  1072. }
  1073. }
  1074. };
  1075. DECLARE_ACHIEVEMENT( CAchievementTF_ParachuteKillGrind, ACHIEVEMENT_TF_PARACHUTE_KILL_GRIND, "TF_PARACHUTE_KILL_GRIND", 5 );
  1076. //----------------------------------------------------------------------------------------------------------------
  1077. class CAchievementTF_MeleeKillClassicRifleSniper : public CBaseTFAchievement
  1078. {
  1079. public:
  1080. void Init()
  1081. {
  1082. SetFlags( ACH_SAVE_GLOBAL );
  1083. SetGoal( 10 );
  1084. SetStoreProgressInSteam( true );
  1085. }
  1086. // server awards this achievement, no other code within achievement necessary
  1087. };
  1088. DECLARE_ACHIEVEMENT( CAchievementTF_MeleeKillClassicRifleSniper, ACHIEVEMENT_TF_MELEE_KILL_CLASSIC_RIFLE_SNIPER, "TF_MELEE_KILL_CLASSIC_RIFLE_SNIPER", 5 );
  1089. //----------------------------------------------------------------------------------------------------------------
  1090. class CAchievementTF_KillChargingDemo : public CBaseTFAchievement
  1091. {
  1092. public:
  1093. void Init()
  1094. {
  1095. SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
  1096. SetGoal( 1 );
  1097. }
  1098. virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
  1099. {
  1100. CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
  1101. if ( pTFVictim && ( pAttacker == C_TFPlayer::GetLocalTFPlayer() ) )
  1102. {
  1103. if ( pTFVictim->m_Shared.InCond( TF_COND_SHIELD_CHARGE ) )
  1104. {
  1105. IncrementCount();
  1106. }
  1107. }
  1108. }
  1109. };
  1110. DECLARE_ACHIEVEMENT( CAchievementTF_KillChargingDemo, ACHIEVEMENT_TF_KILL_CHARGING_DEMO, "TF_KILL_CHARGING_DEMO", 5 );
  1111. //----------------------------------------------------------------------------------------------------------------
  1112. class CAchievementTFTaunt_CongaKill : public CBaseTFAchievement
  1113. {
  1114. public:
  1115. void Init()
  1116. {
  1117. SetFlags( ACH_SAVE_GLOBAL );
  1118. SetGoal( 1 );
  1119. }
  1120. virtual void ListenForEvents( void )
  1121. {
  1122. ListenForGameEvent( "conga_kill" );
  1123. }
  1124. void FireGameEvent_Internal( IGameEvent *event )
  1125. {
  1126. if ( FStrEq( event->GetName(), "conga_kill" ) )
  1127. {
  1128. if ( event->GetInt( "index" ) == GetLocalPlayerIndex() )
  1129. {
  1130. int iNewIndex = m_Times.AddToTail();
  1131. m_Times[iNewIndex] = gpGlobals->curtime;
  1132. // we only care about the last three times we killed someone
  1133. if ( m_Times.Count() > 3 )
  1134. {
  1135. m_Times.Remove( 0 );
  1136. }
  1137. if ( m_Times.Count() == 3 )
  1138. {
  1139. if ( m_Times.Tail() - m_Times.Head() <= 5.0 )
  1140. {
  1141. IncrementCount();
  1142. }
  1143. }
  1144. }
  1145. }
  1146. }
  1147. private:
  1148. CUtlVector< float > m_Times;
  1149. };
  1150. DECLARE_ACHIEVEMENT( CAchievementTFTaunt_CongaKill, ACHIEVEMENT_TF_TAUNT_CONGA_KILL, "TF_TAUNT_CONGA_KILL", 5 );
  1151. //----------------------------------------------------------------------------------------------------------------
  1152. class CAchievementTFTaunt_CongaLine : public CBaseTFAchievement
  1153. {
  1154. public:
  1155. void Init()
  1156. {
  1157. SetFlags( ACH_SAVE_GLOBAL );
  1158. SetGoal( 1 );
  1159. }
  1160. // server awards this achievement, no other code within achievement necessary
  1161. };
  1162. DECLARE_ACHIEVEMENT( CAchievementTFTaunt_CongaLine, ACHIEVEMENT_TF_TAUNT_CONGA_LINE, "TF_TAUNT_CONGA_LINE", 5 );
  1163. //----------------------------------------------------------------------------------------------------------------
  1164. class CAchievementTFTaunt_RPSRock : public CBaseTFAchievement
  1165. {
  1166. public:
  1167. void Init()
  1168. {
  1169. SetFlags( ACH_SAVE_GLOBAL );
  1170. SetGoal( 1 );
  1171. m_iCount = 0;
  1172. }
  1173. virtual void ListenForEvents( void )
  1174. {
  1175. ListenForGameEvent( "rps_taunt_event" );
  1176. }
  1177. void FireGameEvent_Internal( IGameEvent *event )
  1178. {
  1179. if ( FStrEq( event->GetName(), "rps_taunt_event" ) )
  1180. {
  1181. if ( event->GetInt( "winner" ) == GetLocalPlayerIndex() )
  1182. {
  1183. m_iCount = 0;
  1184. }
  1185. else if ( event->GetInt( "loser" ) == GetLocalPlayerIndex() )
  1186. {
  1187. if ( event->GetInt( "loser_rps" ) == 0 ) // 0:rock 1:paper 2:scissors
  1188. {
  1189. m_iCount++;
  1190. if ( m_iCount >= 3 )
  1191. {
  1192. IncrementCount();
  1193. }
  1194. }
  1195. else
  1196. {
  1197. m_iCount = 0;
  1198. }
  1199. }
  1200. }
  1201. }
  1202. private:
  1203. int m_iCount;
  1204. };
  1205. DECLARE_ACHIEVEMENT( CAchievementTFTaunt_RPSRock, ACHIEVEMENT_TF_TAUNT_RPS_ROCK, "TF_TAUNT_RPS_ROCK", 5 );
  1206. //----------------------------------------------------------------------------------------------------------------
  1207. class CAchievementTFTaunt_RPSScissors : public CBaseTFAchievement
  1208. {
  1209. public:
  1210. void Init()
  1211. {
  1212. SetFlags( ACH_SAVE_GLOBAL );
  1213. SetGoal( 1 );
  1214. m_iCount = 0;
  1215. }
  1216. virtual void ListenForEvents( void )
  1217. {
  1218. ListenForGameEvent( "rps_taunt_event" );
  1219. }
  1220. void FireGameEvent_Internal( IGameEvent *event )
  1221. {
  1222. if ( FStrEq( event->GetName(), "rps_taunt_event" ) )
  1223. {
  1224. if ( event->GetInt( "winner" ) == GetLocalPlayerIndex() )
  1225. {
  1226. if ( event->GetInt( "winner_rps" ) == 2 ) // 0:rock 1:paper 2:scissors
  1227. {
  1228. m_iCount++;
  1229. if ( m_iCount >= 3 )
  1230. {
  1231. IncrementCount();
  1232. }
  1233. }
  1234. else
  1235. {
  1236. m_iCount = 0;
  1237. }
  1238. }
  1239. else if ( event->GetInt( "loser" ) == GetLocalPlayerIndex() )
  1240. {
  1241. m_iCount = 0;
  1242. }
  1243. }
  1244. }
  1245. private:
  1246. int m_iCount;
  1247. };
  1248. DECLARE_ACHIEVEMENT( CAchievementTFTaunt_RPSScissors, ACHIEVEMENT_TF_TAUNT_RPS_SCISSORS, "TF_TAUNT_RPS_SCISSORS", 5 );
  1249. //----------------------------------------------------------------------------------------------------------------
  1250. class CAchievementTFTaunt_DosidoMeleeKill : public CBaseTFAchievement
  1251. {
  1252. public:
  1253. void Init()
  1254. {
  1255. SetFlags( ACH_SAVE_GLOBAL );
  1256. SetGoal( 10 );
  1257. SetStoreProgressInSteam( true );
  1258. }
  1259. // server awards this achievement, no other code within achievement necessary
  1260. };
  1261. DECLARE_ACHIEVEMENT( CAchievementTFTaunt_DosidoMeleeKill, ACHIEVEMENT_TF_TAUNT_DOSIDO_MELLE_KILL, "TF_TAUNT_DOSIDO_MELLE_KILL", 5 );
  1262. //----------------------------------------------------------------------------------------------------------------
  1263. class CAchievementTFTaunt_TauntWhileCapping : public CBaseTFAchievement
  1264. {
  1265. public:
  1266. void Init()
  1267. {
  1268. SetFlags( ACH_SAVE_GLOBAL );
  1269. SetGoal( 10 );
  1270. SetStoreProgressInSteam( true );
  1271. }
  1272. // server awards this achievement, no other code within achievement necessary
  1273. };
  1274. DECLARE_ACHIEVEMENT( CAchievementTFTaunt_TauntWhileCapping, ACHIEVEMENT_TF_TAUNT_WHILE_CAPPING, "TF_TAUNT_WHILE_CAPPING", 5 );
  1275. //----------------------------------------------------------------------------------------------------------------
  1276. class CAchievementTF_PassTimeHat : public CBaseTFAchievement
  1277. {
  1278. public:
  1279. void Init()
  1280. {
  1281. SetFlags( ACH_SAVE_GLOBAL );
  1282. SetGoal( 1 );
  1283. }
  1284. // server awards this achievement, no other code within achievement necessary
  1285. };
  1286. DECLARE_ACHIEVEMENT( CAchievementTF_PassTimeHat, ACHIEVEMENT_TF_PASS_TIME_HAT, "TF_PASS_TIME_HAT", 5 );
  1287. //----------------------------------------------------------------------------------------------------------------
  1288. class CAchievementTF_PassTimeGrind : public CBaseTFAchievement
  1289. {
  1290. public:
  1291. void Init()
  1292. {
  1293. SetFlags( ACH_SAVE_GLOBAL );
  1294. SetGoal( 10 );
  1295. SetStoreProgressInSteam( true );
  1296. }
  1297. virtual void ListenForEvents()
  1298. {
  1299. ListenForGameEvent( "teamplay_round_win" );
  1300. }
  1301. void FireGameEvent_Internal( IGameEvent *event )
  1302. {
  1303. if ( TFGameRules() && TFGameRules()->IsPasstimeMode() )
  1304. {
  1305. if ( FStrEq( event->GetName(), "teamplay_round_win" ) )
  1306. {
  1307. // Were we on the winning team?
  1308. int iTeam = event->GetInt( "team" );
  1309. if ( ( iTeam >= FIRST_GAME_TEAM ) && ( iTeam == GetLocalPlayerTeam() ) )
  1310. {
  1311. IncrementCount();
  1312. }
  1313. }
  1314. }
  1315. }
  1316. };
  1317. DECLARE_ACHIEVEMENT( CAchievementTF_PassTimeGrind, ACHIEVEMENT_TF_PASS_TIME_GRIND, "TF_PASS_TIME_GRIND", 5 );
  1318. #endif // CLIENT_DLL