diff options
Diffstat (limited to 'game/shared/tf/achievements_tf_demoman.cpp')
| -rw-r--r-- | game/shared/tf/achievements_tf_demoman.cpp | 1885 |
1 files changed, 1885 insertions, 0 deletions
diff --git a/game/shared/tf/achievements_tf_demoman.cpp b/game/shared/tf/achievements_tf_demoman.cpp new file mode 100644 index 0000000..6a48a58 --- /dev/null +++ b/game/shared/tf/achievements_tf_demoman.cpp @@ -0,0 +1,1885 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + + +#include "cbase.h" + +#ifdef CLIENT_DLL + +#include "achievementmgr.h" +#include "baseachievement.h" +#include "tf_hud_statpanel.h" +#include "c_tf_team.h" +#include "c_tf_player.h" +#include "c_tf_playerresource.h" +#include "tf_gamerules.h" +#include "achievements_tf.h" +#include "c_tf_objective_resource.h" +#include "tf_weapon_shovel.h" +#include "movevars_shared.h" + +//====================================================================================================================================== +// DEMOMAN ACHIEVEMENT PACK +//====================================================================================================================================== + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_KillSoldierGrind : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS ); + SetGoal( 500 ); + SetStoreProgressInSteam( true ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + if ( !pVictim || !pVictim->IsPlayer() ) + return; + + if ( pAttacker == C_BasePlayer::GetLocalPlayer() ) + { + // no friendly fire kills + if ( pVictim->GetTeamNumber() != pAttacker->GetTeamNumber() ) + { + CTFPlayer *pTFVictim = ToTFPlayer( pVictim ); + if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SOLDIER ) ) + { + // we killed a soldier + IncrementCount(); + } + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillSoldierGrind, ACHIEVEMENT_TF_DEMOMAN_KILL_SOLDIER_GRIND, "TF_DEMOMAN_KILL_SOLDIER_GRIND", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_DestroyBuildingsWithMedic : public CBaseTFAchievement +{ + DECLARE_CLASS( CAchievementTFDemoman_DestroyBuildingsWithMedic, CBaseTFAchievement ); + + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + m_iBuildingsDestroyed = 0; + } + + virtual void ListenForEvents() + { + BaseClass::ListenForEvents(); + ListenForGameEvent( "player_invulned" ); + ListenForGameEvent( "object_destroyed" ); + } + + virtual void FireGameEvent_Internal( IGameEvent *event ) + { + if ( FStrEq( event->GetName(), "player_invulned" ) ) + { + int iTarget = engine->GetPlayerForUserID( event->GetInt( "userid" ) ); + CBaseEntity *pPlayer = UTIL_PlayerByIndex( iTarget ); + C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( pPlayer == pLocalPlayer ) + { + m_iBuildingsDestroyed = 0; + } + } + else if ( Q_strcmp( event->GetName(), "object_destroyed" ) == 0 ) + { + int iAttackerIndex = engine->GetPlayerForUserID( event->GetInt( "attacker" ) ); + if ( iAttackerIndex > 0 ) + { + CBaseEntity *pAttacker = UTIL_PlayerByIndex( iAttackerIndex ); + C_TFPlayer *pTFPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( pTFPlayer && pTFPlayer == pAttacker ) + { + if ( pTFPlayer->m_Shared.InCond( TF_COND_INVULNERABLE ) || pTFPlayer->m_Shared.InCond( TF_COND_CRITBOOSTED ) || + pTFPlayer->m_Shared.InCond( TF_COND_INVULNERABLE_WEARINGOFF ) ) + { + m_iBuildingsDestroyed++; + if ( m_iBuildingsDestroyed >= 5 ) + { + IncrementCount(); + } + } + } + } + } + else + { + BaseClass::FireGameEvent_Internal( event ); + } + } + +private: + int m_iBuildingsDestroyed; +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DestroyBuildingsWithMedic, ACHIEVEMENT_TF_DEMOMAN_DESTROY_BUILDINGS_WITH_MEDIC, "TF_DEMOMAN_DESTROY_BUILDINGS_WITH_MEDIC", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_DecapitateCloakedSpy : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + CTFPlayer *pTFVictim = ToTFPlayer( pVictim ); + if ( !pTFVictim ) + return; + + CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() ); + if ( !pLocalPlayer ) + return; + + if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SPY ) && pTFVictim->m_Shared.InCond( TF_COND_STEALTHED ) ) + { + int customdmg = event->GetInt( "customkill" ); + if ( customdmg == TF_DMG_CUSTOM_DECAPITATION ) + { + IncrementCount(); + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DecapitateCloakedSpy, ACHIEVEMENT_TF_DEMOMAN_DECAPITATE_CLOAKED_SPY, "TF_DEMOMAN_DECAPITATE_CLOAKED_SPY", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_KillWithDirectPipe : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 50 ); + SetStoreProgressInSteam( true ); + } + + // Kill 50 enemies with direct hits from the pipebomb launcher + // The server (tf_player) awards this achievement - no code necessary +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillWithDirectPipe, ACHIEVEMENT_TF_DEMOMAN_KILL_X_WITH_DIRECTPIPE, "TF_DEMOMAN_KILL_X_WITH_DIRECTPIPE", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_BounceAndKill : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + SetDefLessFunc( m_BouncedPlayers ); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "teamplay_round_active" ); + ListenForGameEvent( "localplayer_respawn" ); + ListenForGameEvent( "player_hurt" ); + m_BouncedPlayers.RemoveAll(); + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + if ( FStrEq( event->GetName(), "teamplay_round_active" ) || + FStrEq( event->GetName(), "localplayer_respawn" ) ) + { + m_BouncedPlayers.RemoveAll(); + } + else if ( FStrEq( event->GetName(), "player_hurt" ) ) + { + int iAttacker = engine->GetPlayerForUserID( event->GetInt( "attacker" ) ); + CBasePlayer *pAttacker = UTIL_PlayerByIndex( iAttacker ); + if ( pAttacker == C_TFPlayer::GetLocalTFPlayer() ) + { + int iVictim = engine->GetPlayerForUserID( event->GetInt( "userid" ) ); + CBasePlayer *pVictim = UTIL_PlayerByIndex( iVictim ); + if ( pVictim ) + { + bool bVictimGrounded = pVictim->GetFlags() & FL_ONGROUND; + if ( bVictimGrounded ) + { + int iIndex = m_BouncedPlayers.Find( pVictim->GetUserID() ); + if ( iIndex != m_BouncedPlayers.InvalidIndex() ) + { + // they're already in our list + m_BouncedPlayers[iIndex] = gpGlobals->curtime; + } + else + { + // we need to add them + m_BouncedPlayers.Insert( pVictim->GetUserID(), gpGlobals->curtime ); + } + } + } + } + } + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + if ( pVictim == C_BasePlayer::GetLocalPlayer() ) + { + m_BouncedPlayers.RemoveAll(); + return; + } + + if ( pAttacker == C_BasePlayer::GetLocalPlayer() ) + { + C_TFPlayer *pTFVictim = ToTFPlayer( pVictim ); + if ( pTFVictim && !( pTFVictim->GetFlags() & FL_ONGROUND ) ) + { + int iIndex = m_BouncedPlayers.Find( pTFVictim->GetUserID() ); + if ( iIndex != m_BouncedPlayers.InvalidIndex() ) + { + if ( gpGlobals->curtime < m_BouncedPlayers[iIndex] + 4.0f ) + { + IncrementCount(); + } + } + } + } + } + + CUtlMap< int, float > m_BouncedPlayers; // userID and most recent time they were bounced +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_BounceAndKill, ACHIEVEMENT_TF_DEMOMAN_BOUNCE_AND_KILL, "TF_DEMOMAN_BOUNCE_AND_KILL", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_DecapitatePlayers : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL ); + SetGoal( 50 ); + SetStoreProgressInSteam( true ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() ); + if ( !pLocalPlayer ) + return; + + if ( pLocalPlayer != pAttacker ) + return; + + int customdmg = event->GetInt( "customkill" ); + if ( customdmg == TF_DMG_CUSTOM_DECAPITATION ) + { + IncrementCount(); + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DecapitatePlayers, ACHIEVEMENT_TF_DEMOMAN_DECAPITATE_PLAYERS, "TF_DEMOMAN_DECAPITATE_PLAYERS", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_DecapitatePlayersFast : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "teamplay_round_active" ); + ListenForGameEvent( "localplayer_respawn" ); + m_iTimelyDecapitations = 0; + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + if ( FStrEq( event->GetName(), "teamplay_round_active" ) || + FStrEq( event->GetName(), "localplayer_respawn" ) ) + { + m_iTimelyDecapitations = 0; + } + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() ); + if ( !pLocalPlayer ) + return; + + if ( pLocalPlayer != pAttacker ) + return; + + int customdmg = event->GetInt( "customkill" ); + if ( customdmg == TF_DMG_CUSTOM_DECAPITATION ) + { + if ( (m_iTimelyDecapitations == 0) || ((m_iTimelyDecapitations > 0) && (gpGlobals->curtime < m_flLastDecapTime + 10.f)) ) + { + m_iTimelyDecapitations++; + } + else + { + m_iTimelyDecapitations = 1; + } + + m_flLastDecapTime = gpGlobals->curtime; + + if ( m_iTimelyDecapitations == 4 ) + { + IncrementCount(); + } + } + } + + int m_iTimelyDecapitations; + float m_flLastDecapTime; +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DecapitatePlayersFast, ACHIEVEMENT_TF_DEMOMAN_DECAPITATE_PLAYERS_FAST, "TF_DEMOMAN_DECAPITATE_PLAYERS_FAST", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFSoldier_DuoDemomanKills : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 10 ); + SetStoreProgressInSteam( true ); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "player_death" ); + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + if ( FStrEq( event->GetName(), "player_death" ) ) + { + int iAttackerIndex = engine->GetPlayerForUserID( event->GetInt( "attacker" ) ); + if ( iAttackerIndex == 0 ) + return; + CTFPlayer *pAttacker = ToTFPlayer( UTIL_PlayerByIndex( iAttackerIndex ) ); + if ( !pAttacker ) + return; + + int iAssisterIndex = engine->GetPlayerForUserID( event->GetInt( "assister" ) ); + if ( iAssisterIndex == 0 ) + return; + CTFPlayer *pAssister = ToTFPlayer( UTIL_PlayerByIndex( iAssisterIndex ) ); + if ( !pAssister ) + return; + + if ( pAttacker == C_BasePlayer::GetLocalPlayer() && pAssister->IsPlayerClass( TF_CLASS_DEMOMAN ) ) + { + // We are the attacker and the assist is from a demoman. + IncrementCount(); + return; + } + + if ( pAssister == C_BasePlayer::GetLocalPlayer() && pAttacker->IsPlayerClass( TF_CLASS_DEMOMAN ) ) + { + // We are the assister and the kill is from a demoman. + IncrementCount(); + return; + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFSoldier_DuoDemomanKills, ACHIEVEMENT_TF_DEMOMAN_DUO_DEMOMAN_KILLS, "TF_DEMOMAN_DUO_DEMOMAN_KILLS", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_KillTwoDuringStickyJump : public CBaseTFAchievement +{ + // While airborne after a sticky-jump, kill at least two enemy players + + void Init() + { + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "sticky_jump" ); + ListenForGameEvent( "sticky_jump_landed" ); + ListenForGameEvent( "teamplay_round_active" ); + ListenForGameEvent( "localplayer_respawn" ); + m_iKilledDuringStickyJump = 0; + m_bStickyJumping = false; + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + if ( FStrEq( event->GetName(), "teamplay_round_active" ) || + FStrEq( event->GetName(), "localplayer_respawn" ) ) + { + m_iKilledDuringStickyJump = 0; + m_bStickyJumping = false; + } + else if ( FStrEq( event->GetName(), "sticky_jump_landed" ) ) + { + int iIndex = engine->GetPlayerForUserID( event->GetInt( "userid" ) ); + if ( iIndex > 0 ) + { + C_TFPlayer *pJumper = ToTFPlayer( UTIL_PlayerByIndex( iIndex ) ); + + if ( pJumper && ( pJumper == C_BasePlayer::GetLocalPlayer() ) ) + { + m_iKilledDuringStickyJump = 0; + m_bStickyJumping = false; + } + } + + return; + } + else if ( FStrEq( event->GetName(), "sticky_jump" ) ) + { + int iIndex = engine->GetPlayerForUserID( event->GetInt( "userid" ) ); + if ( iIndex > 0 ) + { + C_TFPlayer *pJumper = ToTFPlayer( UTIL_PlayerByIndex( iIndex ) ); + + if ( pJumper && ( pJumper == C_BasePlayer::GetLocalPlayer() ) ) + { + m_iKilledDuringStickyJump = 0; + m_bStickyJumping = true; + } + } + + return; + } + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + if ( !pVictim || !pVictim->IsPlayer() ) + return; + + if ( pAttacker && ( pAttacker == C_BasePlayer::GetLocalPlayer() ) ) + { + if ( m_bStickyJumping ) + { + m_iKilledDuringStickyJump++; + + if ( m_iKilledDuringStickyJump == 2 ) + { + IncrementCount(); + } + } + } + } + +private: + bool m_bStickyJumping; + int m_iKilledDuringStickyJump; +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillTwoDuringStickyJump, ACHIEVEMENT_TF_DEMOMAN_KILL_TWO_DURING_STICKYJUMP, "TF_DEMOMAN_KILL_TWO_DURING_STICKYJUMP", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_KillPlayerAfterTeleport : public CBaseTFAchievement +{ + // Kill an enemy player within X seconds of them teleporting in + + void Init() + { + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() ); + if ( !pLocalPlayer ) + return; + + if ( !pVictim || !pVictim->IsPlayer() ) + return; + + C_TFPlayer *pTFVictim = ToTFPlayer( pVictim ); + if ( event->GetInt( "weaponid" ) == TF_WEAPON_GRENADE_PIPEBOMB ) + { + if ( pTFVictim->m_Shared.InCond( TF_COND_TELEPORTED ) && ( gpGlobals->curtime - pTFVictim->m_Shared.GetTimeTeleEffectAdded() <= 5.0 ) ) + { + IncrementCount(); + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillPlayerAfterTeleport, ACHIEVEMENT_TF_DEMOMAN_KILL_PLAYER_AFTER_TP, "TF_DEMOMAN_KILL_PLAYER_AFTER_TP", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_DominateEngineerThreeTimes : public CBaseTFAchievement +{ + // Dominate three Engineers + + void Init() + { + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL ); + SetGoal( 3 ); + SetStoreProgressInSteam( true ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() ); + if ( !pLocalPlayer ) + return; + + if ( !pVictim || !pVictim->IsPlayer() ) + return; + + bool bDomination = event->GetInt( "death_flags" ) & TF_DEATH_DOMINATION; + if ( bDomination == true ) + { + CTFPlayer *pTFVictim = ToTFPlayer( pVictim ); + if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_ENGINEER ) ) + { + IncrementCount(); + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DominateEngineerThreeTimes, ACHIEVEMENT_TF_DEMOMAN_DOMINATE_THREE_ENGINEERS, "TF_DEMOMAN_DOMINATE_THREE_ENGINEERS", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_KillBuildingDirectHit : public CBaseTFAchievement +{ + // Kill an Engineer building that you can't see with a direct hit from your Grenade Launcher + // Server awards this achievement (tf_obj.cpp) - no other code necessary + + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillBuildingDirectHit, ACHIEVEMENT_TF_DEMOMAN_KILL_BUILDING_DIRECT_HIT, "TF_DEMOMAN_KILL_BUILDING_DIRECT_HIT", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_MeleeKillWhileJumping : public CBaseTFAchievement +{ + // Get a melee kill while in sticky jump + + void Init() + { + SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS ); + SetGoal( 1 ); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "sticky_jump" ); + ListenForGameEvent( "sticky_jump_landed" ); + ListenForGameEvent( "teamplay_round_active" ); + ListenForGameEvent( "localplayer_respawn" ); + m_bStickyJumping = false; + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + if ( FStrEq( event->GetName(), "teamplay_round_active" ) || + FStrEq( event->GetName(), "localplayer_respawn" ) ) + { + m_bStickyJumping = false; + } + else if ( FStrEq( event->GetName(), "sticky_jump_landed" ) ) + { + int iIndex = engine->GetPlayerForUserID( event->GetInt( "userid" ) ); + if ( iIndex > 0 ) + { + C_TFPlayer *pJumper = ToTFPlayer( UTIL_PlayerByIndex( iIndex ) ); + + if ( pJumper && ( pJumper == C_BasePlayer::GetLocalPlayer() ) ) + { + m_bStickyJumping = false; + } + } + + return; + } + else if ( FStrEq( event->GetName(), "sticky_jump" ) ) + { + int iIndex = engine->GetPlayerForUserID( event->GetInt( "userid" ) ); + if ( iIndex > 0 ) + { + C_TFPlayer *pJumper = ToTFPlayer( UTIL_PlayerByIndex( iIndex ) ); + + if ( pJumper && ( pJumper == C_BasePlayer::GetLocalPlayer() ) ) + { + m_bStickyJumping = true; + } + } + + return; + } + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + if ( !pVictim || !pVictim->IsPlayer() ) + return; + + if ( pAttacker && ( pAttacker == C_BasePlayer::GetLocalPlayer() ) ) + { + if ( m_bStickyJumping ) + { + if ( event->GetInt( "weaponid" ) == TF_WEAPON_BOTTLE || event->GetInt( "weaponid" ) == TF_WEAPON_SWORD ) + { + IncrementCount(); + } + } + } + } + +private: + bool m_bStickyJumping; +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_MeleeKillWhileJumping, ACHIEVEMENT_TF_DEMOMAN_MELEE_KILL_WHILE_STICKYJUMPING, "TF_DEMOMAN_MELEE_KILL_WHILE_STICKYJUMPING", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_KillEngiSentryDispenser : public CBaseTFAchievement +{ + // Kill an Engineer, his Sentry and Dispenser, with one sticky detonation + + void Init() + { + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + SetDefLessFunc( m_Engineers ); + SetDefLessFunc( m_SentryDestroyed ); + SetDefLessFunc( m_DispenserDestroyed ); + ResetTracking(); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "teamplay_round_active" ); + ListenForGameEvent( "localplayer_respawn" ); + ListenForGameEvent( "object_destroyed" ); + ResetTracking(); + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + if ( FStrEq( event->GetName(), "teamplay_round_active" ) || + FStrEq( event->GetName(), "localplayer_respawn" ) ) + { + ResetTracking(); + } + else if ( FStrEq( event->GetName(), "object_destroyed" ) ) + { + if ( event->GetInt( "weaponid" ) == TF_WEAPON_GRENADE_PIPEBOMB ) + { + int iAttacker = engine->GetPlayerForUserID( event->GetInt( "attacker" ) ); + CBaseEntity *pAttacker = UTIL_PlayerByIndex( iAttacker ); + C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); + + if ( !pLocalPlayer ) + return; + + if ( pLocalPlayer != pAttacker ) + return; + + int iEngineer = engine->GetPlayerForUserID( event->GetInt( "userid" ) ); + int iObject = event->GetInt( "objecttype" ); + + if ( iObject == OBJ_SENTRYGUN ) + { + int iIndex = m_SentryDestroyed.Find( iEngineer ); + if ( iIndex != m_SentryDestroyed.InvalidIndex() ) + { + // already tracking them, update the time + m_SentryDestroyed[iIndex] = gpGlobals->curtime; + } + else + { + m_SentryDestroyed.Insert( iEngineer, gpGlobals->curtime ); + } + + CheckGoalMet(); + } + if ( iObject == OBJ_DISPENSER ) + { + int iIndex = m_DispenserDestroyed.Find( iEngineer ); + if ( iIndex != m_DispenserDestroyed.InvalidIndex() ) + { + // already tracking them, update the time + m_DispenserDestroyed[iIndex] = gpGlobals->curtime; + } + else + { + m_DispenserDestroyed.Insert( iEngineer, gpGlobals->curtime ); + } + + CheckGoalMet(); + } + } + } + } + + void ResetTracking( void ) + { + m_Engineers.RemoveAll(); + m_SentryDestroyed.RemoveAll(); + m_DispenserDestroyed.RemoveAll(); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + if ( event->GetInt( "weaponid" ) == TF_WEAPON_GRENADE_PIPEBOMB ) + { + CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() ); + if ( !pLocalPlayer ) + return; + + if ( !pVictim || !pVictim->IsPlayer() ) + return; + + CTFPlayer *pTFVictim = ToTFPlayer( pVictim ); + if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_ENGINEER ) ) + { + int iEngineer = engine->GetPlayerForUserID( event->GetInt( "userid" ) ); + m_Engineers.InsertOrReplace( iEngineer, gpGlobals->curtime ); + + CheckGoalMet(); + } + } + } + + void CheckGoalMet( void ) + { + FOR_EACH_MAP_FAST ( m_Engineers, numEngineers ) + { + int iEngineer = m_Engineers.Key( numEngineers ); + + // Destroyed their Sentry? + int iSentry = m_SentryDestroyed.Find( iEngineer ); + if ( iSentry != m_SentryDestroyed.InvalidIndex() ) + { + // Destroyed their Dispenser? + int iDispenser = m_DispenserDestroyed.Find( iEngineer ); + if ( iDispenser != m_DispenserDestroyed.InvalidIndex() ) + { + // All three at the same time? +// if ( ( m_Engineers[numEngineers] == m_SentryDestroyed[iSentry] ) && +// ( m_Engineers[numEngineers] == m_DispenserDestroyed[iDispenser] ) ) + if ( ( gpGlobals->curtime < m_SentryDestroyed[iSentry] + 0.1f ) && + ( gpGlobals->curtime < m_DispenserDestroyed[iDispenser] + 0.1f ) && + ( gpGlobals->curtime < m_Engineers[numEngineers] + 0.1f ) ) + { + IncrementCount(); + } + } + } + } + } + +private: + CUtlMap< int, float > m_SentryDestroyed; // Engineer userID and time sentry was destroyed + CUtlMap< int, float > m_DispenserDestroyed; // Engineer userID and time dispenser was destroyed + CUtlMap< int, float > m_Engineers; // Engineers we've killed and the time +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillEngiSentryDispenser, ACHIEVEMENT_TF_DEMOMAN_KILL_ENGI_SENTRY_DISPENSER, "TF_DEMOMAN_KILL_ENGI_SENTRY_DISPENSER", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_DecapitateEqualizer : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + CTFPlayer *pTFVictim = ToTFPlayer( pVictim ); + if ( !pTFVictim ) + return; + + if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SOLDIER ) ) + { + CTFShovel *pShovel = dynamic_cast<CTFShovel*>( pTFVictim->GetActiveTFWeapon() ); + if ( pShovel && (pShovel->GetShovelType() == SHOVEL_DAMAGE_BOOST) ) + { + int customdmg = event->GetInt( "customkill" ); + if ( customdmg == TF_DMG_CUSTOM_DECAPITATION ) + { + IncrementCount(); + } + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DecapitateEqualizer, ACHIEVEMENT_TF_DEMOMAN_DECAPITATE_EQUALIZER, "TF_DEMOMAN_DECAPITATE_EQUALIZER", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_DecapitateNemesis : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + CTFPlayer *pTFVictim = ToTFPlayer( pVictim ); + if ( !pTFVictim ) + return; + + if ( pTFVictim && pTFVictim->IsNemesisOfLocalPlayer() ) + { + int customdmg = event->GetInt( "customkill" ); + if ( customdmg == TF_DMG_CUSTOM_DECAPITATION ) + { + IncrementCount(); + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DecapitateNemesis, ACHIEVEMENT_TF_DEMOMAN_DECAPITATE_NEMESIS, "TF_DEMOMAN_DECAPITATE_NEMESIS", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_DamageGrind : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1000000 ); + SetStoreProgressInSteam( true ); + } + + void OnPlayerStatsUpdate() + { + ClassStats_t &classStats = CTFStatPanel::GetClassStats( TF_CLASS_DEMOMAN ); + int iOldCount = m_iCount; + m_iCount = classStats.accumulated.m_iStat[TFSTAT_BLASTDAMAGE]; + if ( m_iCount != iOldCount ) + { + m_pAchievementMgr->SetDirty( true ); + } + + if ( IsLocalTFPlayerClass( TF_CLASS_DEMOMAN ) ) + { + EvaluateNewAchievement(); + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DamageGrind, ACHIEVEMENT_TF_DEMOMAN_DAMAGE_GRIND, "TF_DEMOMAN_DAMAGE_GRIND", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_KillXCapping : public CBaseTFAchievement +{ + // Kill "x" players that are capping or pushing the cart with one detonation, "y" times + // Server checks for this achievement - no code necessary + + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 3 ); + SetStoreProgressInSteam( true ); + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillXCapping, ACHIEVEMENT_TF_DEMOMAN_KILL_X_CAPPING_ONEDET, "TF_DEMOMAN_KILL_X_CAPPING_ONEDET", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_KillXDefending : public CBaseTFAchievement +{ + // Kill "x" players that are defending + // Server checks for this achievement - no code necessary + + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 25 ); + SetStoreProgressInSteam( true ); + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillXDefending, ACHIEVEMENT_TF_DEMOMAN_KILL_X_DEFENDING, "TF_DEMOMAN_KILL_X_DEFENDING", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_DestroyBuildings : public CBaseTFAchievement +{ + // Destroy "x" buildings + + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 50 ); + SetStoreProgressInSteam( true ); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "object_destroyed" ); + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + if ( FStrEq( event->GetName(), "object_destroyed" ) ) + { + int iIndex = engine->GetPlayerForUserID( event->GetInt( "attacker" ) ); + CBaseEntity *pDestroyer = UTIL_PlayerByIndex( iIndex ); + C_TFPlayer *pTFPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( pDestroyer == pTFPlayer ) + { + IncrementCount(); + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DestroyBuildings, ACHIEVEMENT_TF_DEMOMAN_DESTROY_BUILDINGS_GRIND, "TF_DEMOMAN_DESTROY_BUILDINGS_GRIND", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_KillXHeaviesAtFull : public CBaseTFAchievement +{ + // Kill 3 Heavies from full health with a single Sticky detonation + // Server checks for this achievement - no code necessary + + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 3 ); + SetStoreProgressInSteam( true ); + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillXHeaviesAtFull, ACHIEVEMENT_TF_DEMOMAN_KILL_X_HEAVIES_FULLHP_ONEDET, "TF_DEMOMAN_KILL_X_HEAVIES_FULLHP_ONEDET", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_KillXScoutsPyros : public CBaseTFAchievement +{ + // Kill 25 Scouts or Pyros with the grenade launcher + + void Init() + { + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL ); + SetGoal( 25 ); + SetStoreProgressInSteam( true ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() ); + if ( !pLocalPlayer ) + return; + + if ( !pVictim || !pVictim->IsPlayer() ) + return; + + C_TFPlayer *pTFVictim = ToTFPlayer( pVictim ); + if ( pTFVictim->IsPlayerClass( TF_CLASS_PYRO ) || pTFVictim->IsPlayerClass( TF_CLASS_SCOUT ) ) + { + if ( event->GetInt( "weaponid" ) == TF_WEAPON_GRENADE_DEMOMAN ) + { + IncrementCount(); + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillXScoutsPyros, ACHIEVEMENT_TF_DEMOMAN_KILL_X_SCOUTS_PYROS, "TF_DEMOMAN_KILL_X_SCOUTS_PYROS", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_TauntKill : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER ); + SetGoal( 1 ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + // was this a taunt kill? + if ( event->GetInt( "customkill" ) == TF_DMG_CUSTOM_TAUNTATK_BARBARIAN_SWING ) + { + IncrementCount(); + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_TauntKill, ACHIEVEMENT_TF_DEMOMAN_TAUNT_KILL, "TF_DEMOMAN_TAUNT_KILL", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_ChargeKill : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER ); + SetGoal( 1 ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + // was this a taunt kill? + if ( event->GetInt( "customkill" ) == TF_DMG_CUSTOM_CHARGE_IMPACT ) + { + IncrementCount(); + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_ChargeKill, ACHIEVEMENT_TF_DEMOMAN_CHARGE_KILL, "TF_DEMOMAN_CHARGE_KILL", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_CritSwordKill : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER ); + SetGoal( 5 ); + SetStoreProgressInSteam( true ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + // was this a charge kill with the sword? + int nDamageBits = event->GetInt( "damagebits" ); + if ( (nDamageBits & DMG_CRITICAL) && (event->GetInt( "customkill" ) == TF_DMG_CUSTOM_DECAPITATION) ) + { + IncrementCount(); + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_CritSwordKill, ACHIEVEMENT_TF_DEMOMAN_CRIT_SWORD_KILL, "TF_DEMOMAN_CRIT_SWORD_KILL", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_AirBurstKills : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER ); + SetGoal( 30 ); + SetStoreProgressInSteam( true ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + // was this an air burst kill? + if ( event->GetInt( "customkill" ) == TF_DMG_CUSTOM_AIR_STICKY_BURST ) + { + IncrementCount(); + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_AirBurstKills, ACHIEVEMENT_TF_DEMOMAN_AIR_BURST_KILLS, "TF_DEMOMAN_AIR_BURST_KILLS", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_StickyJumpCap : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL | ACH_FILTER_ATTACKER_IS_PLAYER ); + SetGoal( 1 ); + } + + virtual void ListenForEvents( void ) + { + ListenForGameEvent( "teamplay_round_active" ); + ListenForGameEvent( "teamplay_point_startcapture" ); + ListenForGameEvent( "controlpoint_endtouch" ); + ListenForGameEvent( "teamplay_point_captured" ); + ListenForGameEvent( "sticky_jump_landed" ); + ResetTracking(); + } + + void CheckGoalMet( void ) + { + // If sticky_jump_landed and startcapture times occurred roughly together... + float fTemp1 = 0; + float fTemp2 = 0; + if ( m_fLandTime > m_fCapStartTime ) + { + fTemp1 = m_fLandTime; + fTemp2 = m_fCapStartTime; + } + else + { + fTemp1 = m_fCapStartTime; + fTemp2 = m_fLandTime; + } + + float fDelta = fTemp1 - fTemp2; + if ( fDelta <= 0.5f ) + { + // Check if we successfully capped the point we landed on + if ( m_bCapped ) + { + IncrementCount(); + } + } + } + + void ResetTracking( void ) + { + m_bCapped = false; + m_fLandTime = 0; + m_fCapStartTime = 0; + m_iCapID = -1; + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + // Only check CP maps + if ( TFGameRules() && TFGameRules()->GetGameType() != TF_GAMETYPE_CP && TFGameRules()->GetGameType() != TF_GAMETYPE_ARENA ) + return; + + // Capture the time we land + if ( FStrEq( event->GetName(), "sticky_jump_landed" ) ) + { + int iIndex = engine->GetPlayerForUserID( event->GetInt( "userid" ) ); + if ( iIndex > 0 ) + { + C_TFPlayer *pJumper = ToTFPlayer( UTIL_PlayerByIndex( iIndex ) ); + + if ( pJumper && ( pJumper == C_BasePlayer::GetLocalPlayer() ) ) + { + m_fLandTime = gpGlobals->curtime; + CheckGoalMet(); + } + } + + return; + } + // Capture the time we start capping + else if ( FStrEq( event->GetName(), "teamplay_point_startcapture" ) ) + { + const char *cappers = event->GetString( "cappers" ); + for ( int i = 0; i < Q_strlen( cappers ); i++ ) + { + C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( !pLocalPlayer ) + return; + + int iPlayerIndex = (int) cappers[i]; + CTFPlayer *pCapper = ToTFPlayer( UTIL_PlayerByIndex( iPlayerIndex ) ); + if ( pCapper && ( pCapper == C_BasePlayer::GetLocalPlayer() ) ) + { + m_fCapStartTime = gpGlobals->curtime; + m_iCapID = event->GetInt( "cp" ); + CheckGoalMet(); + } + } + } + else if ( FStrEq( event->GetName(), "teamplay_point_captured" ) ) + { + C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( !pLocalPlayer ) + return; + + int iTeam = event->GetInt( "team" ); + if ( iTeam == pLocalPlayer->GetTeamNumber() ) + { + const char *cappers = event->GetString( "cappers" ); + for ( int i = 0; i < Q_strlen( cappers ); i++ ) + { + int iPlayerIndex = (int) cappers[i]; + CTFPlayer *pCapper = ToTFPlayer( UTIL_PlayerByIndex( iPlayerIndex ) ); + if ( pCapper && ( pCapper == C_BasePlayer::GetLocalPlayer() ) ) + { + if ( m_iCapID == event->GetInt( "cp" ) ) + { + m_bCapped = true; + CheckGoalMet(); + } + } + } + } + } + else if ( FStrEq( event->GetName(), "controlpoint_endtouch" ) ) + { + int iPlayerIndex = event->GetInt( "player", 0 ); + if ( iPlayerIndex == GetLocalPlayerIndex() ) + { + // We failed to take the point + ResetTracking(); + } + } + else if ( FStrEq( event->GetName(), "teamplay_round_active" ) ) + { + // Reset tracking at the start of a new round + ResetTracking(); + } + } + +private: + float m_fLandTime; + float m_fCapStartTime; + bool m_bCapped; + int m_iCapID; +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_StickyJumpCap, ACHIEVEMENT_TF_DEMOMAN_STICKYJUMP_CAP, "TF_DEMOMAN_STICKYJUMP_CAP", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_FreezeTaunt : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + // Give opponents freezecams of you taunting + // server awards this achievement, no other code within achievement necessary +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_FreezeTaunt, ACHIEVEMENT_TF_DEMOMAN_FREEZECAM_SMILE, "TF_DEMOMAN_FREEZECAM_SMILE", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_FreezeTauntRump : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + // Give opponents freezecams of you taunting + // server awards this achievement, no other code within achievement necessary +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_FreezeTauntRump, ACHIEVEMENT_TF_DEMOMAN_FREEZECAM_RUMP, "TF_DEMOMAN_FREEZECAM_RUMP", 5 ); + + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_EnvironmentalKill : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_KILL_ENEMY_EVENTS ); + SetGoal( 1 ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + CTFPlayer *pTFVictim = ToTFPlayer( pVictim ); + if ( !pTFVictim ) + return; + + CTFPlayer *pLocalPlayer = ToTFPlayer( CBasePlayer::GetLocalPlayer() ); + if ( !pLocalPlayer ) + return; + + if ( pTFVictim->m_Shared.GetWeaponKnockbackID() == pLocalPlayer->GetUserID() ) + { + int custom = event->GetInt( "customkill" ); + int damagebits = event->GetInt( "damagebits" ); + if ( ( damagebits & DMG_VEHICLE ) || // They were hit by a freakin' train! + ( pAttacker && pAttacker->IsBrushModel() ) || // They were smashed by the world! Gah! + ( !pAttacker || (pAttacker == pVictim) ) || // He killed himself! + ( custom == TF_DMG_CUSTOM_SUICIDE ) || + ( custom == TF_DMG_CUSTOM_TRIGGER_HURT ) ) // A trigger-hurt got him! + { + IncrementCount(); + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_EnvironmentalKill, ACHIEVEMENT_TF_DEMOMAN_ENVIRONMENTAL_KILL, "TF_DEMOMAN_ENVIRONMENTAL_KILL", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_DestroyStickyBombs : public CBaseTFAchievement +{ + // Destroy X stickybombs with the Scottish Defender + + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 100 ); + SetStoreProgressInSteam( true ); + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_DestroyStickyBombs, ACHIEVEMENT_TF_DEMOMAN_DESTROY_X_STICKYBOMBS, "TF_DEMOMAN_DESTROY_X_STICKYBOMBS", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_StickyJumpDistance : public CBaseTFAchievement +{ + DECLARE_CLASS( CAchievementTFDemoman_StickyJumpDistance, CBaseTFAchievement ); + + void Init() + { + SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_KILL_EVENTS ); + SetGoal( 1 ); + ResetTracking(); + } + + virtual bool IsActive() + { + return BaseClass::IsActive(); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "teamplay_round_active" ); + ListenForGameEvent( "localplayer_respawn" ); + ListenForGameEvent( "sticky_jump" ); + ListenForGameEvent( "sticky_jump_landed" ); + ResetTracking(); + } + + void ResetTracking( void ) + { + ClearThink(); + m_vecStartJump = vec3_origin; + } + + void CheckJump( void ) + { + CTFPlayer *pLocalTFPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() ); + if ( pLocalTFPlayer ) + { + // someone has messed with gravity, so reset our tracking + if ( GetCurrentGravity() != 800.0f ) + { + ResetTracking(); + return; + } + + Vector vecCurrent = pLocalTFPlayer->GetAbsOrigin(); + vecCurrent.z = 0; + float flDistSqr = (vecCurrent - m_vecStartJump).Length2DSqr(); + if ( flDistSqr > (2048 * 2048) ) + { + IncrementCount(); + } + } + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + const char *pszEvent = event->GetName(); + + if ( FStrEq( pszEvent, "teamplay_round_active" ) || + FStrEq( pszEvent, "localplayer_respawn" ) ) + { + ResetTracking(); + } + else if ( FStrEq( pszEvent, "sticky_jump" ) ) + { + int iUserID = event->GetInt( "userid" ); + + CTFPlayer *pLocalTFPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() ); + if ( pLocalTFPlayer && pLocalTFPlayer->GetUserID() == iUserID ) + { + m_vecStartJump = pLocalTFPlayer->GetAbsOrigin(); + m_vecStartJump.z = 0; + SetNextThink( 0.1 ); + } + } + else if ( FStrEq( pszEvent, "sticky_jump_landed" ) ) + { + int iUserID = event->GetInt( "userid" ); + + CTFPlayer *pLocalTFPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() ); + if ( pLocalTFPlayer && pLocalTFPlayer->GetUserID() == iUserID ) + { + CheckJump(); + ResetTracking(); + } + } + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + if ( !pVictim || !pVictim->IsPlayer() ) + return; + + if ( pVictim == C_BasePlayer::GetLocalPlayer() ) + { + ResetTracking(); + } + } + + virtual void Think( void ) + { + CheckJump(); + SetNextThink( 0.1 ); + } + +private: + Vector m_vecStartJump; +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_StickyJumpDistance, ACHIEVEMENT_TF_DEMOMAN_STICKJUMP_DISTANCE, "TF_DEMOMAN_STICKJUMP_DISTANCE", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_Kill3WithDetonation : public CBaseTFAchievement +{ + // Destroy 3 players with a single pipebomb + + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_Kill3WithDetonation, ACHIEVEMENT_TF_DEMOMAN_KILL3_WITH_DETONATION, "TF_DEMOMAN_KILL3_WITH_DETONATION", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_KillXSappingSpies : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS ); + SetGoal( 20 ); + SetStoreProgressInSteam( true ); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "player_sapped_object" ); + m_hTargets.Purge(); + } + + int FindSpyInList( int iUserID ) + { + for ( int i = m_hTargets.Count() - 1; i >= 0; i-- ) + { + if ( m_hTargets[i].flTime < gpGlobals->curtime ) + { + // time has run out on this one + m_hTargets.Remove( i ); + continue; + } + + if ( m_hTargets[i].nSpyUserID == iUserID ) + return i; + } + + return -1; + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + if ( pAttacker == C_BasePlayer::GetLocalPlayer() ) + { + CTFPlayer *pTFVictim = ToTFPlayer( pVictim ); + if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SPY ) ) + { + int iIndex = FindSpyInList( pTFVictim->GetUserID() ); + if ( iIndex != -1 ) + { + IncrementCount(); + m_hTargets.Remove( iIndex ); + } + } + } + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + const char *pszEventName = event->GetName(); + + if ( FStrEq( pszEventName, "player_sapped_object" ) ) + { + int nUserID = event->GetInt( "userid" ); + int iIndex = FindSpyInList( nUserID ); + if ( iIndex == -1 ) + { + iIndex = m_hTargets.AddToTail(); + m_hTargets[iIndex].nSpyUserID = nUserID; + } + m_hTargets[iIndex].flTime = gpGlobals->curtime + 5.0; + } + } + +private: + struct targets_t + { + int nSpyUserID; + float flTime; + }; + + CUtlVector<targets_t> m_hTargets; +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillXSappingSpies, ACHIEVEMENT_TF_DEMOMAN_KILLXSAPPINGSPIES, "TF_DEMOMAN_KILLXSAPPINGSPIES", 5 ); + + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_Kill3WithPipeSetup : public CBaseTFAchievement +{ + // Kill 3 players in separate explosions without placing new sticky bombs + + void Init() + { + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_FILTER_ATTACKER_IS_PLAYER | ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + virtual void ListenForEvents() + { + ResetCounts(); + } + + void ResetCounts() + { + m_iConsecutiveKillsWithoutRefiring = 0; + m_flPrevKillTime = 0; + m_iPipebombCount = 0; + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() ); + if ( !pLocalPlayer ) + return; + + if ( event->GetInt( "weaponid" ) == TF_WEAPON_GRENADE_PIPEBOMB ) + { + if ( !m_iConsecutiveKillsWithoutRefiring ) + { + // We're starting. + m_iConsecutiveKillsWithoutRefiring = 1; + m_flPrevKillTime = gpGlobals->curtime; + m_iPipebombCount = pLocalPlayer->GetNumActivePipebombs(); + SetNextThink( 0.1 ); + } + else if ( (gpGlobals->curtime - m_flPrevKillTime) > 0.2 ) // Make sure it wasn't in the same detonation + { + m_iConsecutiveKillsWithoutRefiring++; + m_flPrevKillTime = gpGlobals->curtime; + if ( m_iConsecutiveKillsWithoutRefiring >= 3 ) + { + IncrementCount(); + } + } + } + } + + virtual void Think( void ) + { + CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() ); + if ( !pLocalPlayer ) + return; + + int nPipes = pLocalPlayer->GetNumActivePipebombs(); + if ( m_iPipebombCount < nPipes ) + { + // They laid new pipes. We're done. + ResetCounts(); + } + else + { + m_iPipebombCount = nPipes; + SetNextThink( 0.1 ); + } + } + +private: + int m_iPipebombCount; + int m_iConsecutiveKillsWithoutRefiring; + float m_flPrevKillTime; +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_Kill3WithPipeSetup, ACHIEVEMENT_TF_DEMOMAN_KILL3_WITH_PIPE_SETUPS, "TF_DEMOMAN_KILL3_WITH_PIPE_SETUPS", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_AchieveProgress1 : public CAchievement_AchievedCount +{ +public: + DECLARE_CLASS( CAchievementTFDemoman_AchieveProgress1, CAchievement_AchievedCount ); + void Init() + { + BaseClass::Init(); + SetAchievementsRequired( 5, ACHIEVEMENT_TF_DEMOMAN_START_RANGE, ACHIEVEMENT_TF_DEMOMAN_END_RANGE ); + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_AchieveProgress1, ACHIEVEMENT_TF_DEMOMAN_ACHIEVE_PROGRESS1, "TF_DEMOMAN_ACHIEVE_PROGRESS1", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_AchieveProgress2 : public CAchievement_AchievedCount +{ +public: + DECLARE_CLASS( CAchievementTFDemoman_AchieveProgress2, CAchievement_AchievedCount ); + void Init() + { + BaseClass::Init(); + SetAchievementsRequired( 11, ACHIEVEMENT_TF_DEMOMAN_START_RANGE, ACHIEVEMENT_TF_DEMOMAN_END_RANGE ); + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_AchieveProgress2, ACHIEVEMENT_TF_DEMOMAN_ACHIEVE_PROGRESS2, "TF_DEMOMAN_ACHIEVE_PROGRESS2", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_AchieveProgress3 : public CAchievement_AchievedCount +{ +public: + DECLARE_CLASS( CAchievementTFDemoman_AchieveProgress3, CAchievement_AchievedCount ); + void Init() + { + BaseClass::Init(); + SetAchievementsRequired( 17, ACHIEVEMENT_TF_DEMOMAN_START_RANGE, ACHIEVEMENT_TF_DEMOMAN_END_RANGE ); + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_AchieveProgress3, ACHIEVEMENT_TF_DEMOMAN_ACHIEVE_PROGRESS3, "TF_DEMOMAN_ACHIEVE_PROGRESS3", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_ParachuteKillGroup : public CBaseTFAchievement +{ +public: + void Init() + { + SetFlags( ACH_LISTEN_KILL_EVENTS | ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + ResetTracking(); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "parachute_deploy" ); + ListenForGameEvent( "parachute_holster" ); + } + + void ResetTracking( void ) + { + m_nKills = 0; + m_bParachuteDeployed = false; + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + const char *pszEvent = event->GetName(); + + if ( FStrEq( pszEvent, "parachute_deploy" ) ) + { + if ( event->GetInt( "index" ) == GetLocalPlayerIndex() ) + { + ResetTracking(); + m_bParachuteDeployed = true; + } + } + else if ( FStrEq( pszEvent, "parachute_holster" ) ) + { + if ( event->GetInt( "index" ) == GetLocalPlayerIndex() ) + { + ResetTracking(); + } + } + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + if ( pVictim ) + { + // Local player died + if ( pVictim == C_BasePlayer::GetLocalPlayer() ) + { + ResetTracking(); + } + else if ( pAttacker == C_BasePlayer::GetLocalPlayer() ) + { + if ( m_bParachuteDeployed ) + { + m_nKills++; + if ( m_nKills >= 3 ) + { + IncrementCount(); + } + } + } + } + } + +private: + int m_nKills; + bool m_bParachuteDeployed; +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_ParachuteKillGroup, ACHIEVEMENT_TF_DEMOMAN_PARACHUTE_KILL_GROUP, "TF_DEMOMAN_PARACHUTE_KILL_GROUP", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_ParachuteDistance : public CBaseTFAchievement +{ +public: + void Init() + { + SetFlags( ACH_LISTEN_KILL_EVENTS | ACH_SAVE_GLOBAL ); + SetGoal( 1233619 ); + SetStoreProgressInSteam( true ); + ResetTracking(); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "parachute_deploy" ); + ListenForGameEvent( "parachute_holster" ); + } + + void ResetTracking( void ) + { + ClearThink(); + m_flLastZ = 0.0; + } + + void CheckHeight( void ) + { + CBasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pLocalPlayer ) + { + float flCurrentZ = pLocalPlayer->GetAbsOrigin().z; + float flDela = m_flLastZ - flCurrentZ; + + // make sure we've fallen....we may have been pushed upwards + if ( flDela > 0.0f ) + { + IncrementCount( ( int )( flDela ) ); + } + + m_flLastZ = flCurrentZ; + } + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + const char *pszEvent = event->GetName(); + + if ( FStrEq( pszEvent, "parachute_deploy" ) ) + { + if ( event->GetInt( "index" ) == GetLocalPlayerIndex() ) + { + CBasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pLocalPlayer ) + { + m_flLastZ = pLocalPlayer->GetAbsOrigin().z; + SetNextThink( 0.1 ); + } + } + } + else if ( FStrEq( pszEvent, "parachute_holster" ) ) + { + if ( event->GetInt( "index" ) == GetLocalPlayerIndex() ) + { + ResetTracking(); + } + } + } + + virtual void Think( void ) + { + CheckHeight(); + SetNextThink( 0.1 ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + // Local player died + if ( pVictim == C_BasePlayer::GetLocalPlayer() ) + { + ResetTracking(); + } + } + +private: + float m_flLastZ; +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_ParachuteDistance, ACHIEVEMENT_TF_DEMOMAN_PARACHUTE_DISTANCE, "TF_DEMOMAN_PARACHUTE_DISTANCE", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_ParachuteKillParachute : public CBaseTFAchievement +{ +public: + void Init() + { + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + CTFPlayer *pTFAttacker = ToTFPlayer( pAttacker ); + CTFPlayer *pTFVictim = ToTFPlayer( pVictim ); + if ( pTFAttacker && pTFVictim && ( pTFAttacker == C_TFPlayer::GetLocalTFPlayer() ) ) + { + if ( ( pTFAttacker->m_Shared.InCond( TF_COND_PARACHUTE_DEPLOYED ) ) && ( pTFVictim->m_Shared.InCond( TF_COND_PARACHUTE_DEPLOYED ) ) ) + { + IncrementCount(); + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_ParachuteKillParachute, ACHIEVEMENT_TF_DEMOMAN_PARACHUTE_KILL_PARACHUTE, "TF_DEMOMAN_PARACHUTE_KILL_PARACHUTE", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_KillPlayerYouDidntSee : public CBaseTFAchievement +{ +public: + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + // server awards this achievement, no other code within achievement necessary +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_KillPlayerYouDidntSee, ACHIEVEMENT_TF_DEMOMAN_KILL_PLAYER_YOU_DIDNT_SEE, "TF_DEMOMAN_KILL_PLAYER_YOU_DIDNT_SEE", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_QuickKills : public CBaseTFAchievement +{ +public: + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "kill_refills_meter" ); + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + if ( FStrEq( event->GetName(), "kill_refills_meter" ) ) + { + if ( event->GetInt( "index" ) == GetLocalPlayerIndex() ) + { + int iNewIndex = m_Times.AddToTail(); + m_Times[iNewIndex] = gpGlobals->curtime; + + // we only care about the last three times we killed someone + if ( m_Times.Count() > 3 ) + { + m_Times.Remove( 0 ); + } + + if ( m_Times.Count() == 3 ) + { + if ( m_Times.Tail() - m_Times.Head() <= 6.0 ) + { + IncrementCount(); + } + } + } + } + } + +private: + CUtlVector< float > m_Times; +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_QuickKills, ACHIEVEMENT_TF_DEMOMAN_QUICK_KILLS, "TF_DEMOMAN_QUICK_KILLS", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFDemoman_ChargeKillChargingDemo : public CBaseTFAchievement +{ +public: + void Init() + { + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + CTFPlayer *pTFAttacker = ToTFPlayer( pAttacker ); + CTFPlayer *pTFVictim = ToTFPlayer( pVictim ); + + if ( pTFAttacker && pTFVictim && ( pTFAttacker == C_TFPlayer::GetLocalTFPlayer() ) ) + { + if ( pTFAttacker->m_Shared.InCond( TF_COND_SHIELD_CHARGE ) && pTFVictim->m_Shared.InCond( TF_COND_SHIELD_CHARGE ) ) + { + IncrementCount(); + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFDemoman_ChargeKillChargingDemo, ACHIEVEMENT_TF_DEMOMAN_CHARGE_KILL_CHARGING_DEMO, "TF_DEMOMAN_CHARGE_KILL_CHARGING_DEMO", 5 ); + +#endif // CLIENT_DLL + + + |