diff options
Diffstat (limited to 'game/shared/tf/achievements_tf.cpp')
| -rw-r--r-- | game/shared/tf/achievements_tf.cpp | 1495 |
1 files changed, 1495 insertions, 0 deletions
diff --git a/game/shared/tf/achievements_tf.cpp b/game/shared/tf/achievements_tf.cpp new file mode 100644 index 0000000..b481805 --- /dev/null +++ b/game/shared/tf/achievements_tf.cpp @@ -0,0 +1,1495 @@ +//========= 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 "econ_wearable.h" +#include "achievements_tf.h" + +// NVNT include for tf2 damage +#include "haptics/haptic_utils.h" + +CAchievementMgr g_AchievementMgrTF; // global achievement mgr for TF + +bool CheckWinNoEnemyCaps( IGameEvent *event, int iRole ); + +// 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 +// because it can in some cases take a client several minutes to connect with respect to when the server considers the game underway +#define TF_FULL_ROUND_GRACE_PERIOD ( 4 * 60.0f ) + +bool IsLocalTFPlayerClass( int iClass ); + + +bool CBaseTFAchievementSimple::LocalPlayerCanEarn( void ) +{ + if ( TFGameRules() ) + { + bool bMVMAchievement = ( m_iAchievementID >= ACHIEVEMENT_TF_MVM_START_RANGE && m_iAchievementID <= ACHIEVEMENT_TF_MVM_END_RANGE ); + + if ( bMVMAchievement ) + { + if ( !TFGameRules()->IsMannVsMachineMode() || ( GetLocalPlayerTeam() != TF_TEAM_PVE_DEFENDERS ) ) + { + return false; + } + } + else + { + if ( TFGameRules()->IsMannVsMachineMode() ) + { + return false; + } + } + } + + return BaseClass::LocalPlayerCanEarn(); +} + +void CBaseTFAchievementSimple::FireGameEvent( IGameEvent *event ) +{ + if ( !LocalPlayerCanEarn() ) + return; + + BaseClass::FireGameEvent( event ); +} + + +bool CBaseTFAchievement::LocalPlayerCanEarn( void ) +{ + // Swallow game events if we're not allowed to earn achievements, or if the local player isn't the right class + if ( !GameRulesAllowsAchievements() ) + { + return false; + } + + // Determine class & check it + if ( m_iAchievementID >= ACHIEVEMENT_START_CLASS_SPECIFIC && m_iAchievementID <= ACHIEVEMENT_END_CLASS_SPECIFIC ) + { + int iClass = floor( (m_iAchievementID - ACHIEVEMENT_START_CLASS_SPECIFIC) / 100.0f ) + 1; + if ( !IsLocalTFPlayerClass( iClass ) ) + { + return false; + } + } + + return BaseClass::LocalPlayerCanEarn(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFAchievementFullRound::Init() +{ + m_iFlags |= ACH_FILTER_FULL_ROUND_ONLY; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFAchievementFullRound::ListenForEvents() +{ + ListenForGameEvent( "teamplay_round_win" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFAchievementFullRound::FireGameEvent_Internal( IGameEvent *event ) +{ + if ( 0 == Q_strcmp( event->GetName(), "teamplay_round_win" ) ) + { + C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pLocalPlayer ) + { + // is the player currently on a game team? + int iTeam = pLocalPlayer->GetTeamNumber(); + if ( iTeam >= FIRST_GAME_TEAM ) + { + float flRoundTime = event->GetFloat( "round_time", 0 ); + if ( flRoundTime > 0 ) + { + Event_OnRoundComplete( flRoundTime, event ); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFAchievementFullRound::PlayerWasInEntireRound( float flRoundTime ) +{ + float flTeamplayStartTime = m_pAchievementMgr->GetTeamplayStartTime(); + if ( flTeamplayStartTime > 0 ) + { + // has the player been present and on a game team since the start of this round (minus a grace period)? + if ( flTeamplayStartTime < ( gpGlobals->curtime - flRoundTime ) + TF_FULL_ROUND_GRACE_PERIOD ) + return true; + } + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CAchievementTFPlayGameEveryClass : public CTFAchievementFullRound +{ + DECLARE_CLASS( CAchievementTFPlayGameEveryClass, CTFAchievementFullRound ); + void Init() + { + SetFlags( ACH_SAVE_GLOBAL | ACH_HAS_COMPONENTS | ACH_FILTER_FULL_ROUND_ONLY ); + SetGoal( ( TF_LAST_NORMAL_CLASS - 1 ) - TF_FIRST_NORMAL_CLASS + 1 ); //( TF_LAST_NORMAL_CLASS - 1 ) to exclude the new civilian class + BaseClass::Init(); + } + + virtual void Event_OnRoundComplete( float flRoundTime, IGameEvent *event ) + { + float flLastClassChangeTime = m_pAchievementMgr->GetLastClassChangeTime(); + if ( flLastClassChangeTime > 0 ) + { + // has the player been present and not changed class since the start of this round (minus a grace period)? + if ( flLastClassChangeTime < ( gpGlobals->curtime - flRoundTime ) + TF_FULL_ROUND_GRACE_PERIOD ) + { + C_TFPlayer *pTFPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( pTFPlayer ) + { + int iClass = pTFPlayer->GetPlayerClass()->GetClassIndex(); + if ( iClass >= TF_FIRST_NORMAL_CLASS && iClass <= ( TF_LAST_NORMAL_CLASS - 1 ) ) //( TF_LAST_NORMAL_CLASS - 1 ) to exclude the new civilian class + { + // yes, the achievement is satisfied for this class, set the corresponding bit + int iBitNumber =( iClass - TF_FIRST_NORMAL_CLASS ); + EnsureComponentBitSetAndEvaluate( iBitNumber ); + } + } + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFPlayGameEveryClass, ACHIEVEMENT_TF_PLAY_GAME_EVERYCLASS, "TF_PLAY_GAME_EVERYCLASS", 5 ); + +class CAchievementTFPlayGameEveryMap : public CTFAchievementFullRound +{ + DECLARE_CLASS( CAchievementTFPlayGameEveryMap, CTFAchievementFullRound ); + void Init() + { + SetFlags( ACH_SAVE_GLOBAL | ACH_HAS_COMPONENTS | ACH_FILTER_FULL_ROUND_ONLY ); + + static const char *szComponents[] = + { + "cp_dustbowl", "cp_granary", "cp_gravelpit", "cp_well", "ctf_2fort", "tc_hydro" + }; + m_pszComponentNames = szComponents; + m_iNumComponents = ARRAYSIZE( szComponents ); + SetGoal( m_iNumComponents ); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "teamplay_round_win" ); + } + + virtual void Event_OnRoundComplete( float flRoundTime, IGameEvent *event ) + { + float flTeamplayStartTime = m_pAchievementMgr->GetTeamplayStartTime(); + if ( flTeamplayStartTime > 0 ) + { + // has the player been present and on a game team since the start of this round (minus a grace period)? + if ( flTeamplayStartTime < ( gpGlobals->curtime - flRoundTime ) + TF_FULL_ROUND_GRACE_PERIOD ) + { + // yes, the achievement is satisfied for this map, set the corresponding bit + OnComponentEvent( m_pAchievementMgr->GetMapName() ); + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFPlayGameEveryMap, ACHIEVEMENT_TF_PLAY_GAME_EVERYMAP, "TF_PLAY_GAME_EVERYMAP", 5 ); + +class CAchievementTFGetHealPoints : public CBaseTFAchievementSimple +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 25000 ); + } + + void OnPlayerStatsUpdate() + { + ClassStats_t &classStats = CTFStatPanel::GetClassStats( TF_CLASS_MEDIC ); + int iOldCount = m_iCount; + m_iCount = classStats.accumulated.m_iStat[TFSTAT_HEALING]; + if ( m_iCount != iOldCount ) + { + m_pAchievementMgr->SetDirty( true ); + } + + if ( IsLocalTFPlayerClass( TF_CLASS_MEDIC ) ) + { + EvaluateNewAchievement(); + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFGetHealPoints, ACHIEVEMENT_TF_GET_HEALPOINTS, "TF_GET_HEALPOINTS", 5 ); + +class CAchievementTFBurnPlayersInMinimumTime : public CBaseTFAchievementSimple +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + // server awards this achievement, no other code within achievement necessary +}; +DECLARE_ACHIEVEMENT( CAchievementTFBurnPlayersInMinimumTime, ACHIEVEMENT_TF_BURN_PLAYERSINMINIMIMTIME, "TF_BURN_PLAYERSINMINIMUMTIME", 5 ); + +class CAchievementTFGetTurretKills : public CBaseTFAchievementSimple +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + // server awards this achievement, no other code within achievement necessary +}; +DECLARE_ACHIEVEMENT( CAchievementTFGetTurretKills, ACHIEVEMENT_TF_GET_TURRETKILLS, "TF_GET_TURRETKILLS", 5 ); + +class CAchievementTFGetHeadshots: public CBaseTFAchievementSimple +{ + void Init() + { + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL ); + SetGoal( 25 ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + // was this a headshot by this player? + if ( ( pAttacker == C_TFPlayer::GetLocalTFPlayer() ) && ( IsHeadshot(event->GetInt( "customkill" ) ) ) ) + { + // Increment count. Count will also get slammed whenever we get a stats update from server. They should generally agree, + // but server is authoritative. + IncrementCount(); + } + } + + void OnPlayerStatsUpdate() + { + // when stats are updated by server, use most recent stat value + ClassStats_t &classStats = CTFStatPanel::GetClassStats( TF_CLASS_SNIPER ); + int iOldCount = m_iCount; + m_iCount = classStats.accumulated.m_iStat[TFSTAT_HEADSHOTS]; + if ( m_iCount != iOldCount ) + { + m_pAchievementMgr->SetDirty( true ); + } + + if ( IsLocalTFPlayerClass( TF_CLASS_SNIPER ) ) + { + EvaluateNewAchievement(); + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFGetHeadshots, ACHIEVEMENT_TF_GET_HEADSHOTS, "TF_GET_HEADSHOTS", 5 ); + +class CAchievementTFKillNemesis : public CBaseTFAchievementSimple +{ + void Init() + { + SetFlags( ACH_LISTEN_KILL_EVENTS | ACH_SAVE_GLOBAL ); + SetGoal( 5 ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + if ( ( ( event->GetInt( "death_flags" ) & TF_DEATH_REVENGE ) ) && ( pAttacker == C_TFPlayer::GetLocalTFPlayer() ) ) + { + // local player got revenge as primary killer + IncrementCount(); + } + else if ( event->GetInt( "death_flags" ) & TF_DEATH_ASSISTER_REVENGE ) + { + int iAssisterIndex = engine->GetPlayerForUserID( event->GetInt( "assister" ) ); + if ( iAssisterIndex > 0 ) + { + CBaseEntity *pAssister = UTIL_PlayerByIndex( iAssisterIndex ); + if ( pAssister && ( pAssister == C_TFPlayer::GetLocalTFPlayer() ) ) + { + // local player got revenge as assister + IncrementCount(); + } + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFKillNemesis, ACHIEVEMENT_TF_KILL_NEMESIS, "TF_KILL_NEMESIS", 5 ); + +class CAchievementTFGetConsecutiveKillsNoDeaths : public CBaseTFAchievementSimple +{ + void Init() + { + SetFlags( ACH_LISTEN_KILL_EVENTS | ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + m_iConsecutiveKills = 0; + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pLocalPlayer == pVictim ) + { + m_iConsecutiveKills = 0; + } + else if ( pLocalPlayer == pAttacker ) + { + m_iConsecutiveKills++; + if ( 5 == m_iConsecutiveKills ) + { + IncrementCount(); + } + } + } + int m_iConsecutiveKills; +}; +DECLARE_ACHIEVEMENT( CAchievementTFGetConsecutiveKillsNoDeaths, ACHIEVEMENT_TF_GET_CONSECUTIVEKILLS_NODEATHS, "TF_GET_CONSECUTIVEKILLS_NODEATHS", 10 ); + +class CAchievementTFGetHealedByEnemy: public CBaseTFAchievementSimple +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + // server awards this achievement, no other code within achievement necessary +}; +DECLARE_ACHIEVEMENT( CAchievementTFGetHealedByEnemy, ACHIEVEMENT_TF_GET_HEALED_BYENEMY, "TF_GET_HEALED_BYENEMY", 15 ); + +class CAchievementTFPlayGameFriendsOnly : public CBaseTFAchievementSimple +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL | ACH_FILTER_FULL_ROUND_ONLY ); + SetGoal( 1 ); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "teamplay_round_win" ); + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + if ( 0 == Q_strcmp( event->GetName(), "teamplay_round_win" ) ) + { + // Are there at least 7 friends in the game? (at least 8 players total) + if ( CalcPlayersOnFriendsList( 7 ) ) + { + IncrementCount(); + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFPlayGameFriendsOnly, ACHIEVEMENT_TF_PLAY_GAME_FRIENDSONLY, "TF_PLAY_GAME_FRIENDSONLY", 10 ); + +class CAchievementTFWinMultipleGames : public CTFAchievementFullRound +{ + DECLARE_CLASS( CAchievementTFWinMultipleGames, CTFAchievementFullRound ); + void Init() + { + SetFlags( ACH_SAVE_GLOBAL | ACH_FILTER_FULL_ROUND_ONLY ); + SetGoal( 20 ); + BaseClass::Init(); + } + + virtual void Event_OnRoundComplete( float flRoundTime, IGameEvent *event ) + { + C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( pLocalPlayer ) + { + // was the player on the winning team? + int iPlayerTeam = pLocalPlayer->GetTeamNumber(); + int iWinningTeam = event->GetInt( "team" ); + if ( ( iWinningTeam >= FIRST_GAME_TEAM ) && ( iPlayerTeam == iWinningTeam ) ) + { + IncrementCount(); + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFWinMultipleGames, ACHIEVEMENT_TF_WIN_MULTIPLEGAMES, "TF_WIN_MULTIPLEGAMES", 10 ); + +class CAchievementTFGetMultipleKills : public CBaseTFAchievementSimple +{ + void Init() + { + // listen for player kill enemy events, base class will increment count each time that happens + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL ); + SetGoal( 1000 ); + } + + void OnPlayerStatsUpdate() + { + // when stats are updated by server, use most recent stat values + + int iKills = 0; + // get sum of kills per class across all classes to get total kills + 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 + { + ClassStats_t &classStats = CTFStatPanel::GetClassStats( iClass ); + iKills += classStats.accumulated.m_iStat[TFSTAT_KILLS]; + } + + int iOldCount = m_iCount; + m_iCount = iKills; + if ( m_iCount != iOldCount ) + { + m_pAchievementMgr->SetDirty( true ); + } + + EvaluateNewAchievement(); + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFGetMultipleKills, ACHIEVEMENT_TF_GET_MULTIPLEKILLS, "TF_GET_MULTIPLEKILLS", 15 ); + +class CAchievementTFWin2FortNoEnemyCaps : public CBaseTFAchievementSimple +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + SetMapNameFilter( "ctf_2fort" ); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "teamplay_round_win" ); + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + if ( 0 == Q_strcmp( event->GetName(), "teamplay_round_win" ) ) + { + if ( event->GetBool( "was_sudden_death" ) == false ) + { + if ( event->GetInt( "team" ) == GetLocalPlayerTeam() ) + { + // did the enemy team get any flag captures? + C_TFTeam *pEnemyTeam = GetGlobalTFTeam( TF_TEAM_BLUE + TF_TEAM_RED - GetLocalPlayerTeam() ); + if ( 0 == pEnemyTeam->GetFlagCaptures() ) + { + IncrementCount(); + } + } + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFWin2FortNoEnemyCaps, ACHIEVEMENT_TF_WIN_2FORT_NOENEMYCAPS, "TF_WIN_2FORT_NOENEMYCAPS", 5 ); + +class CAchievementTFWinWellMinimumTime : public CBaseTFAchievementSimple +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + SetMapNameFilter( "cp_well" ); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "teamplay_round_win" ); + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + if ( 0 == Q_strcmp( event->GetName(), "teamplay_round_win" ) ) + { + if ( event->GetInt( "team" ) == GetLocalPlayerTeam() ) + { + float flRoundTime = event->GetFloat( "round_time", 0 ); + if ( flRoundTime > 0 && flRoundTime < 5 * 60 ) + { + IncrementCount(); + } + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFWinWellMinimumTime, ACHIEVEMENT_TF_WIN_WELL_MINIMUMTIME, "TF_WIN_WELL_MINIMUMTIME", 10 ); + +class CAchievementTFWinHydroNoEnemyCaps : public CBaseTFAchievementSimple +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL | ACH_FILTER_FULL_ROUND_ONLY ); + SetGoal( 1 ); + SetMapNameFilter( "tc_hydro" ); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "teamplay_round_win" ); + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + // winning hydro with no enemy caps means there were 2 previous minirounds completed (3 total for a shutout) + // and local player's team won the final round + if ( ( 2 == m_pAchievementMgr->GetMiniroundsCompleted() ) && ( CheckWinNoEnemyCaps( event, TEAM_ROLE_NONE ) ) ) + { + IncrementCount(); + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFWinHydroNoEnemyCaps, ACHIEVEMENT_TF_WIN_HYDRO_NOENEMYCAPS, "TF_WIN_HYDRO_NOENEMYCAPS", 20 ); + +class CAchievementTFWinDustbowlNoEnemyCaps : public CBaseTFAchievementSimple +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL | ACH_FILTER_FULL_ROUND_ONLY ); + SetGoal( 1 ); + SetMapNameFilter( "cp_dustbowl" ); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "teamplay_round_win" ); + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + // defending dustbowl with no enemy caps means there were no previous minirounds completed (that would be an attacker capture), + // the player was on the defending team and they won with no enemy caps + if ( ( 0 == m_pAchievementMgr->GetMiniroundsCompleted() ) && CheckWinNoEnemyCaps( event, TEAM_ROLE_DEFENDERS ) ) + { + IncrementCount(); + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFWinDustbowlNoEnemyCaps, ACHIEVEMENT_TF_WIN_DUSTBOWL_NOENEMYCAPS, "TF_WIN_DUSTBOWL_NOENEMYCAPS", 10 ); + +class CAchievementTFWinGravelPitNoEnemyCaps : public CBaseTFAchievementSimple +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + SetMapNameFilter( "cp_gravelpit" ); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "teamplay_round_win" ); + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + // Was player on defenders and won with no enemy caps? + if ( CheckWinNoEnemyCaps( event, TEAM_ROLE_DEFENDERS ) ) + { + IncrementCount(); + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFWinGravelPitNoEnemyCaps, ACHIEVEMENT_TF_WIN_GRAVELPIT_NOENEMYCAPS, "TF_WIN_GRAVELPIT_NOENEMYCAPS", 30 ); + +class CAchievementTFKillEnemiesAfterTeleporting : public CTFAchievementTeleporterTimingKills<CBaseAchievement> +{ + // stub -- all code in parent class +}; +DECLARE_ACHIEVEMENT( CAchievementTFKillEnemiesAfterTeleporting, ACHIEVEMENT_TF_GENERAL_KILL_ENEMIES_AFTER_TELEPORTING, "TF_GENERAL_KILL_ENEMIES_AFTER_TELEPORTING", 10 ); + +//----------------------------------------------------------------------------- +// Purpose: see if a round win was a win for the local player with no enemy caps +//----------------------------------------------------------------------------- +bool CheckWinNoEnemyCaps( IGameEvent *event, int iRole ) +{ + if ( 0 == Q_strcmp( event->GetName(), "teamplay_round_win" ) ) + { + if ( event->GetInt( "team" ) == GetLocalPlayerTeam() ) + { + int iLosingTeamCaps = event->GetInt( "losing_team_num_caps" ); + if ( 0 == iLosingTeamCaps ) + { + C_TFTeam *pLocalTeam = GetGlobalTFTeam( GetLocalPlayerTeam() ); + if ( pLocalTeam ) + { + int iRolePlayer = pLocalTeam->GetRole(); + if ( iRole > TEAM_ROLE_NONE && ( iRolePlayer != iRole ) ) + return false; + return true; + } + } + } + } + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Helper function to determine if local player is specified class +//----------------------------------------------------------------------------- +bool IsLocalTFPlayerClass( int iClass ) +{ + C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); + return( pLocalPlayer && pLocalPlayer->IsPlayerClass( iClass ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: Query if the gamerules allows achievement progress at this time +//----------------------------------------------------------------------------- +bool GameRulesAllowsAchievements( void ) +{ + bool bRetVal = false; + + if ( ( TFGameRules()->State_Get() < GR_STATE_TEAM_WIN ) || + ( TFGameRules()->State_Get() == GR_STATE_STALEMATE ) ) + { + bRetVal = true; + } + + return bRetVal; +} + +//---------------------------------------------------------------------------------------------------------------- +// Receive the PlayerIgnitedInv user message and send out a clientside event for achievements to hook. +void __MsgFunc_PlayerIgnitedInv( bf_read &msg ) +{ + int iPyroEntIndex = (int) msg.ReadByte(); + int iVictimEntIndex = (int) msg.ReadByte(); + int iMedicEntIndex = (int) msg.ReadByte(); + + IGameEvent *event = gameeventmanager->CreateEvent( "player_ignited_inv" ); + if ( event ) + { + event->SetInt( "pyro_entindex", iPyroEntIndex ); + event->SetInt( "victim_entindex", iVictimEntIndex ); + event->SetInt( "medic_entindex", iMedicEntIndex ); + gameeventmanager->FireEventClientSide( event ); + } +} + +// Receive the PlayerIgnited user message and send out a clientside event for achievements to hook. +void __MsgFunc_PlayerIgnited( bf_read &msg ) +{ + int iPyroEntIndex = (int) msg.ReadByte(); + int iVictimEntIndex = (int) msg.ReadByte(); + int iWeaponID = (int) msg.ReadByte(); + + IGameEvent *event = gameeventmanager->CreateEvent( "player_ignited" ); + if ( event ) + { + event->SetInt( "pyro_entindex", iPyroEntIndex ); + event->SetInt( "victim_entindex", iVictimEntIndex ); + event->SetInt( "weaponid", iWeaponID ); + gameeventmanager->FireEventClientSide( event ); + } +} + +// Receive the Damage user message and send out a clientside event for achievements to hook. +void __MsgFunc_Damage( bf_read &msg ) +{ + int iDamage = msg.ReadShort(); + int iDmgBits = msg.ReadLong(); + + IGameEvent *event = gameeventmanager->CreateEvent( "player_damaged" ); + if ( event ) + { + event->SetInt( "amount", iDamage ); + event->SetInt( "type", iDmgBits ); + gameeventmanager->FireEventClientSide( event ); + } + // NVNT START implementing rest of message for damage directions + if(iDamage == 0) + return; // no damage forces for no damage. + + // get the local player. + C_TFPlayer *pLocal = C_TFPlayer::GetLocalTFPlayer(); + if(!pLocal) + return;// if we dont have a local player ignore this message. + + Vector attackerPosition(0,0,0); + if(msg.ReadOneBit()) + { + // if we read one bit then that means we have shooters origin. + msg.ReadBitVec3Coord( attackerPosition ); + }else{ + // if it is non origin, just set the origin below the player + attackerPosition = pLocal->GetAbsOrigin() + Vector(0,0,-10); + } + // get the direction in world + Vector attackDirectionLocal(vec3_origin); + // rotate the direction to the local players view + pLocal->WorldToEntitySpace(attackerPosition, &attackDirectionLocal); + + if ( haptics ) + { + Vector hapticSpace( attackDirectionLocal.y, -attackDirectionLocal.z, attackDirectionLocal.x ); + + hapticSpace.NormalizeInPlace(); + + haptics->ApplyDamageEffect((float)iDamage, iDmgBits, hapticSpace); + } + // NVNT END +} + +// Receive the UpdateAchievement user message and send out a clientside event for achievements to hook. +void __MsgFunc_UpdateAchievement( bf_read &msg ) +{ + int iIndex = (int) msg.ReadShort(); + int nData = (int) msg.ReadShort(); + + g_AchievementMgrTF.UpdateAchievement( iIndex, nData ); +} + +// Receive the PlayerJarated user message and send out a clientside event for achievements to hook. +void __MsgFunc_PlayerJarated( bf_read &msg ) +{ + int iThrowerEntIndex = (int) msg.ReadByte(); + int iVictimEntIndex = (int) msg.ReadByte(); + + IGameEvent *event = gameeventmanager->CreateEvent( "player_jarated" ); + if ( event ) + { + event->SetInt( "thrower_entindex", iThrowerEntIndex ); + event->SetInt( "victim_entindex", iVictimEntIndex ); + gameeventmanager->FireEventClientSide( event ); + } +} + +void __MsgFunc_PlayerJaratedFade( bf_read &msg ) +{ + int iThrowerEntIndex = (int) msg.ReadByte(); + int iVictimEntIndex = (int) msg.ReadByte(); + + IGameEvent *event = gameeventmanager->CreateEvent( "player_jarated_fade" ); + if ( event ) + { + event->SetInt( "thrower_entindex", iThrowerEntIndex ); + event->SetInt( "victim_entindex", iVictimEntIndex ); + + gameeventmanager->FireEventClientSide( event ); + } +} +//This is so dumb. +void __MsgFunc_PlayerShieldBlocked( bf_read &msg ) +{ + int iAttacker = (int) msg.ReadByte(); + int iBlocker = (int) msg.ReadByte(); + + IGameEvent *event = gameeventmanager->CreateEvent( "player_shield_blocked" ); + if ( event ) + { + event->SetInt( "attacker_entindex", iAttacker ); + event->SetInt( "blocker_entindex", iBlocker ); + + gameeventmanager->FireEventClientSide( event ); + } +} + +// Receive the PlayerExtinguished user message and send out a clientside event for achievements to hook. +void __MsgFunc_PlayerExtinguished( bf_read &msg ) +{ + int iMedicEntIndex = (int) msg.ReadByte(); + int iVictimEntIndex = (int) msg.ReadByte(); + + IGameEvent *event = gameeventmanager->CreateEvent( "player_extinguished" ); + if ( event ) + { + event->SetInt( "victim", iVictimEntIndex ); + event->SetInt( "healer", iMedicEntIndex ); + + gameeventmanager->FireEventClientSide( event ); + } +} + +void CAchievementTopScoreboard::Init() +{ + SetFlags( ACH_SAVE_GLOBAL | ACH_FILTER_FULL_ROUND_ONLY ); + SetGoal(1); +} + +void CAchievementTopScoreboard::ListenForEvents() +{ + BaseClass::ListenForEvents(); + ListenForGameEvent( "teamplay_round_active" ); +} + +void CAchievementTopScoreboard::Event_OnRoundComplete( float flRoundTime, IGameEvent *event ) +{ + if ( PlayerWasInEntireRound( flRoundTime ) ) + { + int iLocalTeam = C_TFPlayer::GetLocalTFPlayer()->GetTeamNumber(); + + if ( GetGlobalTFTeam(iLocalTeam) && GetGlobalTFTeam(iLocalTeam)->GetNumPlayers() >= 6 ) + { + if ( g_TF_PR ) + { + bool bHighest = true; + int iLocalScore = g_TF_PR->GetTotalScore( C_TFPlayer::GetLocalTFPlayer()->entindex() ); + + // See if the player's on the top of the scoreboard + for( int playerIndex = 1; playerIndex <= MAX_PLAYERS; playerIndex++ ) + { + if ( !g_PR->IsConnected( playerIndex ) || g_PR->IsLocalPlayer( playerIndex ) ) + continue; + + if ( g_PR->GetTeam(playerIndex) != iLocalTeam ) + continue; + + if ( g_TF_PR->GetTotalScore(playerIndex) > iLocalScore ) + { + bHighest = false; + break; + } + } + + if ( bHighest ) + { + IncrementCount(); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +extern int Training_GetNumCourses(); +extern int Training_GetProgressCount(); +class CAchievementTFCompleteTraining : public CBaseTFAchievementSimple +{ + DECLARE_CLASS( CAchievementTFCompleteTraining, CBaseAchievement ); + void Init() + { + SetFlags( ACH_SAVE_GLOBAL | ACH_HAS_COMPONENTS ); + SetGoal( Training_GetNumCourses() ); + SetStoreProgressInSteam( true ); + SetCount( Training_GetProgressCount() ); + BaseClass::Init(); + } + + virtual void UpdateAchievement( int nData ) + { + SetCount( nData ); + EvaluateNewAchievement(); + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFCompleteTraining, ACHIEVEMENT_TF_COMPLETE_TRAINING, "TF_COMPLETE_TRAINING", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTF_FireWaterJump : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + // server awards this achievement, no other code within achievement necessary +}; +DECLARE_ACHIEVEMENT( CAchievementTF_FireWaterJump, ACHIEVEMENT_TF_FIRE_WATERJUMP, "TF_FIRE_WATERJUMP", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFChristmasCollectGifts : public CBaseTFAchievementSimple +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 3 ); + SetStoreProgressInSteam( true ); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "christmas_gift_grab" ); + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + if ( !TFGameRules()->IsHolidayActive( kHoliday_Christmas ) ) + return; + + if ( Q_strcmp( event->GetName(), "christmas_gift_grab" ) == 0 ) + { + int iPlayer = engine->GetPlayerForUserID( event->GetInt( "userid" ) ); + CBaseEntity *pPlayer = UTIL_PlayerByIndex( iPlayer ); + + if ( pPlayer && pPlayer == C_TFPlayer::GetLocalTFPlayer() ) + { + IncrementCount(); + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTFChristmasCollectGifts, ACHIEVEMENT_TF_CHRISTMAS_COLLECT_GIFTS, "TF_CHRISTMAS_COLLECT_GIFTS", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTF_KillBalloonicornOwners : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL ); + SetGoal( 79 ); + SetStoreProgressInSteam( true ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + CSchemaItemDefHandle pItemDef_Balloonicorn( "Pet Balloonicorn" ); + CSchemaItemDefHandle pItemDef_BalloonicornPromo( "Pet Balloonicorn Promo" ); + CSchemaItemDefHandle pItemDef_BalloonicornPlushPromo( "Pet Balloonicorn Plush Promo" ); + CSchemaItemDefHandle pItemDef_Reindoonicorn( "Pet Reindoonicorn" ); + + C_TFPlayer *pLocalPlayer = ToTFPlayer( C_BasePlayer::GetLocalPlayer() ); + if ( pLocalPlayer ) + { + CTFPlayer *pTFVictim = ToTFPlayer( pVictim ); + + if ( pTFVictim && ( pAttacker == pLocalPlayer ) && ( pTFVictim->GetTeamNumber() != pLocalPlayer->GetTeamNumber() ) ) + { + int nVisionOptInFlags = 0; + CALL_ATTRIB_HOOK_INT_ON_OTHER( pLocalPlayer, nVisionOptInFlags, vision_opt_in_flags ); + + // Does the local player have PyroVision on? + if ( nVisionOptInFlags & TF_VISION_FILTER_PYRO ) + { + // Is the victim wearing the Balloonicorn? + for ( int i = 0 ; i < pTFVictim->GetNumWearables() ; ++i ) + { + C_EconWearable *pWearable = pTFVictim->GetWearable( i ); + if ( pWearable && pWearable->GetAttributeContainer() ) + { + CEconItemView *pItem = pWearable->GetAttributeContainer()->GetItem(); + if ( pItem && pItem->IsValid() ) + { + if ( pItem->GetItemDefinition() == pItemDef_Balloonicorn || + pItem->GetItemDefinition() == pItemDef_BalloonicornPromo || + pItem->GetItemDefinition() == pItemDef_BalloonicornPlushPromo || + pItem->GetItemDefinition() == pItemDef_Reindoonicorn ) + { + IncrementCount(); + } + } + } + } + } + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTF_KillBalloonicornOwners, ACHIEVEMENT_TF_KILL_BALLOONICORN_OWNERS, "TF_KILL_BALLOONICORN_OWNERS", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTF_MultipleBFF : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_LISTEN_KILL_EVENTS | ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + virtual void ListenForEvents( void ) + { + ListenForGameEvent( "remove_nemesis_relationships" ); + + // clear data on level init + m_hBFFs.Purge(); + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + if ( FStrEq( event->GetName(), "remove_nemesis_relationships" ) ) + { + int iPlayerIndex = event->GetInt( "player" ); + if ( iPlayerIndex == GetLocalPlayerIndex() ) + { + // this is the local player, clear our list + m_hBFFs.Purge(); + } + else + { + // is this player in our list? + CTFPlayer *pPlayer = ToTFPlayer( UTIL_PlayerByIndex( iPlayerIndex ) ); + + int index = m_hBFFs.Find( pPlayer ); + if ( index != m_hBFFs.InvalidIndex() ) + { + m_hBFFs.Remove( index ); + } + } + } + } + + void ValidateList( void ) + { + // remove anyone on the local player's team to clean up changing teams, getting + // team balanced, etc., if they're still on the other team, we're fine. + for ( int i = m_hBFFs.Count() - 1 ; i >= 0 ; i-- ) + { + C_TFPlayer *pPlayer = m_hBFFs[i]; + if ( pPlayer->GetTeamNumber() == GetLocalPlayerTeam() ) + { + m_hBFFs.Remove( i ); + } + } + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + C_TFPlayer *pLocalPlayer = ToTFPlayer( C_BasePlayer::GetLocalPlayer() ); + if ( pLocalPlayer ) + { + CTFPlayer *pTFAttacker = ToTFPlayer( pAttacker ); + CTFPlayer *pTFVictim = ToTFPlayer( pVictim ); + int iDeathFlags = event->GetInt( "death_flags" ); + bool bDomination = ( iDeathFlags & TF_DEATH_DOMINATION ) || ( iDeathFlags & TF_DEATH_ASSISTER_DOMINATION ); + bool bRevenge = ( iDeathFlags & TF_DEATH_REVENGE ) || ( iDeathFlags & TF_DEATH_ASSISTER_REVENGE ); + + if ( pTFVictim && ( pTFAttacker == pLocalPlayer ) && bDomination ) + { + ValidateList(); + + int nVisionOptInFlags = 0; + CALL_ATTRIB_HOOK_INT_ON_OTHER( pLocalPlayer, nVisionOptInFlags, vision_opt_in_flags ); + + if ( nVisionOptInFlags & TF_VISION_FILTER_PYRO ) + { + int index = m_hBFFs.Find( pTFVictim ); + if ( index == m_hBFFs.InvalidIndex() ) + { + m_hBFFs.AddToHead( pTFVictim ); + } + + if ( m_hBFFs.Count() >= 2 ) + { + IncrementCount(); + } + } + } + else if ( pTFAttacker && ( pTFVictim == pLocalPlayer ) && bRevenge ) + { + ValidateList(); + + int index = m_hBFFs.Find( pTFAttacker ); + if ( index != m_hBFFs.InvalidIndex() ) + { + m_hBFFs.Remove( index ); + } + } + } + } + +private: + CUtlVector< CHandle<C_TFPlayer> > m_hBFFs; +}; +DECLARE_ACHIEVEMENT( CAchievementTF_MultipleBFF, ACHIEVEMENT_TF_MULTIPLE_BFF, "TF_MULTIPLE_BFF", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTF_TeamPyrovision : public CBaseTFAchievement +{ + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + + SetNextThink( 1.0 ); + } + + virtual void Think( void ) + { + C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pLocalPlayer && ( pLocalPlayer->GetTeamNumber() >= FIRST_GAME_TEAM ) ) + { + int nVisionOptInFlags = 0; + CALL_ATTRIB_HOOK_INT_ON_OTHER( pLocalPlayer, nVisionOptInFlags, vision_opt_in_flags ); + + if ( nVisionOptInFlags & TF_VISION_FILTER_PYRO ) + { + int nCount = 0; + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + C_BasePlayer *pPlayer = UTIL_PlayerByIndex( i ); + if ( !pPlayer ) + continue; + + if ( pPlayer == pLocalPlayer ) + { + nCount++; + } + else if ( pPlayer->GetTeamNumber() == pLocalPlayer->GetTeamNumber() ) + { + int nTempFlags = 0; + CALL_ATTRIB_HOOK_INT_ON_OTHER( pPlayer, nTempFlags, vision_opt_in_flags ); + + if ( nTempFlags & TF_VISION_FILTER_PYRO ) + { + nCount++; + } + } + } + + if ( nCount >= 6 ) + { + IncrementCount(); + ClearThink(); + return; + } + } + } + + SetNextThink( 1.0 ); + } +}; +DECLARE_ACHIEVEMENT( CAchievementTF_TeamPyrovision, ACHIEVEMENT_TF_TEAM_PYROVISION, "TF_TEAM_PYROVISION", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTF_DominateForGoggles : public CBaseTFAchievement +{ + 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 *pTFVictim = ToTFPlayer( pVictim ); + bool bDomination = event->GetInt( "death_flags" ) & TF_DEATH_DOMINATION; + + if ( pTFVictim && ( pAttacker == C_TFPlayer::GetLocalTFPlayer() ) && ( bDomination == true ) ) + { + // are they wearing the PyroVision goggles? + for ( int i = 0 ; i < pTFVictim->GetNumWearables() ; ++i ) + { + C_EconWearable *pWearable = pTFVictim->GetWearable( i ); + if ( pWearable && pWearable->GetAttributeContainer() ) + { + CEconItemView *pItem = pWearable->GetAttributeContainer()->GetItem(); + if ( pItem && pItem->IsValid() ) + { + if ( ( pItem->GetItemDefIndex() == 743 ) || // Autogrant PyroVision Goggles + ( pItem->GetItemDefIndex() == 744 ) ) // PyroVision Goggles + { + IncrementCount(); + } + } + } + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTF_DominateForGoggles, ACHIEVEMENT_TF_DOMINATE_FOR_GOGGLES, "TF_DOMINATE_FOR_GOGGLES", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTF_ParachuteKillGrind : public CBaseTFAchievement +{ +public: + void Init() + { + SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL ); + SetGoal( 10 ); + SetStoreProgressInSteam( true ); + } + + virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event ) + { + CTFPlayer *pTFVictim = ToTFPlayer( pVictim ); + if ( pTFVictim && ( pAttacker == C_TFPlayer::GetLocalTFPlayer() ) ) + { + if ( pTFVictim->m_Shared.InCond( TF_COND_PARACHUTE_DEPLOYED ) ) + { + IncrementCount(); + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTF_ParachuteKillGrind, ACHIEVEMENT_TF_PARACHUTE_KILL_GRIND, "TF_PARACHUTE_KILL_GRIND", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTF_MeleeKillClassicRifleSniper : public CBaseTFAchievement +{ +public: + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 10 ); + SetStoreProgressInSteam( true ); + } + + // server awards this achievement, no other code within achievement necessary +}; +DECLARE_ACHIEVEMENT( CAchievementTF_MeleeKillClassicRifleSniper, ACHIEVEMENT_TF_MELEE_KILL_CLASSIC_RIFLE_SNIPER, "TF_MELEE_KILL_CLASSIC_RIFLE_SNIPER", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTF_KillChargingDemo : 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 *pTFVictim = ToTFPlayer( pVictim ); + if ( pTFVictim && ( pAttacker == C_TFPlayer::GetLocalTFPlayer() ) ) + { + if ( pTFVictim->m_Shared.InCond( TF_COND_SHIELD_CHARGE ) ) + { + IncrementCount(); + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTF_KillChargingDemo, ACHIEVEMENT_TF_KILL_CHARGING_DEMO, "TF_KILL_CHARGING_DEMO", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFTaunt_CongaKill : public CBaseTFAchievement +{ +public: + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + virtual void ListenForEvents( void ) + { + ListenForGameEvent( "conga_kill" ); + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + if ( FStrEq( event->GetName(), "conga_kill" ) ) + { + 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() <= 5.0 ) + { + IncrementCount(); + } + } + } + } + } + +private: + CUtlVector< float > m_Times; +}; +DECLARE_ACHIEVEMENT( CAchievementTFTaunt_CongaKill, ACHIEVEMENT_TF_TAUNT_CONGA_KILL, "TF_TAUNT_CONGA_KILL", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFTaunt_CongaLine : public CBaseTFAchievement +{ +public: + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + // server awards this achievement, no other code within achievement necessary +}; +DECLARE_ACHIEVEMENT( CAchievementTFTaunt_CongaLine, ACHIEVEMENT_TF_TAUNT_CONGA_LINE, "TF_TAUNT_CONGA_LINE", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFTaunt_RPSRock : public CBaseTFAchievement +{ +public: + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + m_iCount = 0; + } + + virtual void ListenForEvents( void ) + { + ListenForGameEvent( "rps_taunt_event" ); + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + if ( FStrEq( event->GetName(), "rps_taunt_event" ) ) + { + if ( event->GetInt( "winner" ) == GetLocalPlayerIndex() ) + { + m_iCount = 0; + } + else if ( event->GetInt( "loser" ) == GetLocalPlayerIndex() ) + { + if ( event->GetInt( "loser_rps" ) == 0 ) // 0:rock 1:paper 2:scissors + { + m_iCount++; + if ( m_iCount >= 3 ) + { + IncrementCount(); + } + } + else + { + m_iCount = 0; + } + } + } + } + +private: + int m_iCount; +}; +DECLARE_ACHIEVEMENT( CAchievementTFTaunt_RPSRock, ACHIEVEMENT_TF_TAUNT_RPS_ROCK, "TF_TAUNT_RPS_ROCK", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFTaunt_RPSScissors : public CBaseTFAchievement +{ +public: + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + m_iCount = 0; + } + + virtual void ListenForEvents( void ) + { + ListenForGameEvent( "rps_taunt_event" ); + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + if ( FStrEq( event->GetName(), "rps_taunt_event" ) ) + { + if ( event->GetInt( "winner" ) == GetLocalPlayerIndex() ) + { + if ( event->GetInt( "winner_rps" ) == 2 ) // 0:rock 1:paper 2:scissors + { + m_iCount++; + if ( m_iCount >= 3 ) + { + IncrementCount(); + } + } + else + { + m_iCount = 0; + } + } + else if ( event->GetInt( "loser" ) == GetLocalPlayerIndex() ) + { + m_iCount = 0; + } + } + } + +private: + int m_iCount; +}; +DECLARE_ACHIEVEMENT( CAchievementTFTaunt_RPSScissors, ACHIEVEMENT_TF_TAUNT_RPS_SCISSORS, "TF_TAUNT_RPS_SCISSORS", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFTaunt_DosidoMeleeKill : public CBaseTFAchievement +{ +public: + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 10 ); + SetStoreProgressInSteam( true ); + } + + // server awards this achievement, no other code within achievement necessary +}; +DECLARE_ACHIEVEMENT( CAchievementTFTaunt_DosidoMeleeKill, ACHIEVEMENT_TF_TAUNT_DOSIDO_MELLE_KILL, "TF_TAUNT_DOSIDO_MELLE_KILL", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTFTaunt_TauntWhileCapping : public CBaseTFAchievement +{ +public: + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 10 ); + SetStoreProgressInSteam( true ); + } + + // server awards this achievement, no other code within achievement necessary +}; +DECLARE_ACHIEVEMENT( CAchievementTFTaunt_TauntWhileCapping, ACHIEVEMENT_TF_TAUNT_WHILE_CAPPING, "TF_TAUNT_WHILE_CAPPING", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTF_PassTimeHat : public CBaseTFAchievement +{ +public: + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 1 ); + } + + // server awards this achievement, no other code within achievement necessary +}; +DECLARE_ACHIEVEMENT( CAchievementTF_PassTimeHat, ACHIEVEMENT_TF_PASS_TIME_HAT, "TF_PASS_TIME_HAT", 5 ); + +//---------------------------------------------------------------------------------------------------------------- +class CAchievementTF_PassTimeGrind : public CBaseTFAchievement +{ +public: + void Init() + { + SetFlags( ACH_SAVE_GLOBAL ); + SetGoal( 10 ); + SetStoreProgressInSteam( true ); + } + + virtual void ListenForEvents() + { + ListenForGameEvent( "teamplay_round_win" ); + } + + void FireGameEvent_Internal( IGameEvent *event ) + { + if ( TFGameRules() && TFGameRules()->IsPasstimeMode() ) + { + if ( FStrEq( event->GetName(), "teamplay_round_win" ) ) + { + // Were we on the winning team? + int iTeam = event->GetInt( "team" ); + if ( ( iTeam >= FIRST_GAME_TEAM ) && ( iTeam == GetLocalPlayerTeam() ) ) + { + IncrementCount(); + } + } + } + } +}; +DECLARE_ACHIEVEMENT( CAchievementTF_PassTimeGrind, ACHIEVEMENT_TF_PASS_TIME_GRIND, "TF_PASS_TIME_GRIND", 5 ); + +#endif // CLIENT_DLL |