diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/server/cstrike/funfact_cs.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/server/cstrike/funfact_cs.cpp')
| -rw-r--r-- | game/server/cstrike/funfact_cs.cpp | 793 |
1 files changed, 793 insertions, 0 deletions
diff --git a/game/server/cstrike/funfact_cs.cpp b/game/server/cstrike/funfact_cs.cpp new file mode 100644 index 0000000..e880359 --- /dev/null +++ b/game/server/cstrike/funfact_cs.cpp @@ -0,0 +1,793 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#include "cbase.h" +#include "cs_gamerules.h" +#include "cs_gamestats.h" +#include "funfactmgr_cs.h" +#include "funfact_cs.h" +#include "../../game/shared/cstrike/weapon_csbase.h" +#include "cs_achievement_constants.h" + +#define FIRST_BLOOD_TIME 45.0f +#define FIRST_KILL_TIME 45.0f +#define SHORT_ROUND_TIME 30.0f +#define MIN_SHOTS_FOR_ACCURACY 10 + +enum FunFactId +{ + FUNFACT_CT_WIN_NO_KILLS, + FUNFACT_T_WIN_NO_KILLS, + FUNFACT_KILL_DEFUSER, + FUNFACT_KILL_RESCUER, + FUNFACT_T_WIN_NO_CASUALTIES, + FUNFACT_CT_WIN_NO_CASUALTIES, + FUNFACT_DAMAGE_WITH_GRENADES, + FUNFACT_KILLS_WITH_GRENADES, + FUNFACT_KILLS_WITH_SINGLE_GRENADE, + FUNFACT_DAMAGE_NO_KILLS, + FUNFACT_KILLED_ENEMIES, + FUNFACT_FIRST_KILL, + FUNFACT_FIRST_BLOOD, + FUNFACT_SHORT_ROUND, + FUNFACT_BEST_ACCURACY, + FUNFACT_KNIFE_KILLS, + FUNFACT_BLIND_KILLS, + FUNFACT_KILLS_WITH_LAST_ROUND, + FUNFACT_DONATED_WEAPONS, + FUNFACT_POSTHUMOUS_KILLS_WITH_GRENADE, + FUNFACT_KNIFE_IN_GUNFIGHT, + FUNFACT_NUM_TIMES_JUMPED, + FUNFACT_FALL_DAMAGE, + FUNFACT_ITEMS_PURCHASED, + FUNFACT_WON_AS_LAST_MEMBER, + FUNFACT_NUMBER_OF_OVERKILLS, + FUNFACT_SHOTS_FIRED, + FUNFACT_MONEY_SPENT, + FUNFACT_SURVIVED_MULTIPLE_ATTACKERS, + FUNFACT_DIED_FROM_MULTIPLE_ATTACKERS, + FUNFACT_DAMAGE_MULTIPLE_ENEMIES, + FUNFACT_GRENADES_THROWN, + FUNFACT_USED_ALL_AMMO, + FUNFACT_DEFENDED_BOMB, + FUNFACT_ITEMS_DROPPED_VALUE, + FUNFACT_KILL_WOUNDED_ENEMIES, + FUNFACT_USED_MULTIPLE_WEAPONS, + FUNFACT_TERRORIST_ACCURACY, + FUNFACT_CT_ACCURACY, + FUNFACT_SAME_UNIFORM_TERRORIST, + FUNFACT_SAME_UNIFORM_CT, + FUNFACT_BEST_TERRORIST_ACCURACY, + FUNFACT_BEST_COUNTERTERRORIST_ACCURACY, + FUNFACT_FALLBACK1, + FUNFACT_FALLBACK2, + FUNFACT_KILLS_HEADSHOTS, + FUNFACT_BROKE_WINDOWS, + FUNFACT_NIGHTVISION_DAMAGE, + FUNFACT_DEFUSED_WITH_DROPPED_KIT, + FUNFACT_KILLED_HALF_OF_ENEMIES, +}; + + +CFunFactHelper *CFunFactHelper::s_pFirst = NULL; + + +//============================================================================= +// Generic evaluation Fun Fact +// This fun fact will evaluate the specified function to determine when it is +// valid. This is basically just a glue class for simple evaluation functions. +//============================================================================= + +// Function type that we use to evaluate our fun facts. The data is returned as ints then floats that are passed in as reference parameters +typedef bool (*fFunFactEval)( int &iPlayer, int &data1, int &data2, int &data3 ); + +class CFunFact_GenericEvalFunction : public FunFactEvaluator +{ +public: + CFunFact_GenericEvalFunction(FunFactId id, const char* szLocalizationToken, float fCoolness, fFunFactEval pfnEval ) : + FunFactEvaluator(id, szLocalizationToken, fCoolness), + m_pfnEval(pfnEval) + {} + + virtual bool Evaluate( FunFactVector& results ) const + { + FunFact funfact; + if (m_pfnEval(funfact.iPlayer, funfact.iData1, funfact.iData2, funfact.iData3)) + { + funfact.id = GetId(); + funfact.szLocalizationToken = GetLocalizationToken(); + funfact.fMagnitude = 0.0f; + results.AddToTail(funfact); + return true; + } + else + return false; + } + + private: + fFunFactEval m_pfnEval; +}; +#define DECLARE_FUNFACT_EVALFUNC(funfactId, szLocalizationToken, fCoolness, pfnEval) \ +static FunFactEvaluator *CreateFunFact_##funfactId( void ) \ +{ \ + return new CFunFact_GenericEvalFunction(funfactId, szLocalizationToken, fCoolness, pfnEval);\ +}; \ +static CFunFactHelper g_##funfactId##_Helper( CreateFunFact_##funfactId ); + + +//============================================================================= +// Per-player evaluation Fun Fact +// Evaluate the function per player and generate a fun fact for each valid or +// highest valid player +//============================================================================= + +namespace EvalFlags +{ + enum Type + { + All = 0x00, + TeamCT = 0x01, + TeamTerrorist = 0x02, + HighestOnly = 0x04, // when not set, generates fun facts for all valid testees + Alive = 0x08, + Dead = 0x10, + WinningTeam = 0x20, + LosingTeam = 0x40, + }; +}; + + +bool PlayerQualifies( const CBasePlayer* pPlayer, int flags ) +{ + if ( (flags & EvalFlags::TeamCT) && pPlayer->GetTeamNumber() != TEAM_CT ) + return false; + if ( (flags & EvalFlags::TeamTerrorist) && pPlayer->GetTeamNumber() != TEAM_TERRORIST ) + return false; + if ( (flags & EvalFlags::Dead) && const_cast<CBasePlayer*>(pPlayer)->IsAlive() ) // IsAlive() really isn't const correct + return false; + if ( (flags & EvalFlags::Alive) && !const_cast<CBasePlayer*>(pPlayer)->IsAlive() ) + return false; + if ( (flags & EvalFlags::WinningTeam) && pPlayer->GetTeamNumber() != CSGameRules()->m_iRoundWinStatus ) + return false; + if ( (flags & EvalFlags::LosingTeam) && pPlayer->GetTeamNumber() == CSGameRules()->m_iRoundWinStatus ) + return false; + return true; +} + + +typedef int (*PlayerEvalFunction)(CCSPlayer* pPlayer); + +class CFunFact_PlayerEvalFunction : public FunFactEvaluator +{ +public: + CFunFact_PlayerEvalFunction(FunFactId id, const char* szLocalizationToken, float fCoolness, PlayerEvalFunction pfnEval, + int iMin, int flags ) : + FunFactEvaluator(id, szLocalizationToken, fCoolness), + m_pfnEval(pfnEval), + m_min(iMin), + m_flags(flags) + {} + + virtual bool Evaluate( FunFactVector& results ) const + { + int iBestValue = 0; + int iBestPlayer = 0; + bool bResult = false; + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CCSPlayer* pPlayer = ToCSPlayer(UTIL_PlayerByIndex( i ) ); + if ( pPlayer ) + { + if (!PlayerQualifies(pPlayer, m_flags)) + continue; + + int iValue = m_pfnEval(pPlayer); + + if (m_flags & EvalFlags::HighestOnly) + { + if ( iValue > iBestValue ) + { + iBestValue = iValue; + iBestPlayer = i; + } + } + else + { + // generate fun facts for any player who meets the validation requirement + if ( iValue >= m_min ) + { + FunFact funfact; + funfact.id = GetId(); + funfact.szLocalizationToken = GetLocalizationToken(); + funfact.iPlayer = i; + funfact.iData1 = iValue; + funfact.fMagnitude = 1.0f - ((float)m_min / iValue); + results.AddToTail(funfact); + bResult = true; + } + } + } + } + if ( (m_flags & EvalFlags::HighestOnly) && iBestValue >= m_min ) + { + FunFact funfact; + funfact.id = GetId(); + funfact.szLocalizationToken = GetLocalizationToken(); + funfact.iPlayer = iBestPlayer; + funfact.iData1 = iBestValue; + funfact.fMagnitude = 1.0f - ((float)m_min / iBestValue); + + results.AddToTail(funfact); + bResult = true; + } + return bResult; + } + +private: + PlayerEvalFunction m_pfnEval; + int m_min; + int m_flags; +}; +#define DECLARE_FUNFACT_PLAYERFUNC(funfactId, szLocalizationToken, fCoolness, pfnEval, iMin, iFlags) \ +static FunFactEvaluator *CreateFunFact_##funfactId( void ) \ +{ \ + return new CFunFact_PlayerEvalFunction(funfactId, szLocalizationToken, fCoolness, pfnEval, iMin, iFlags); \ +}; \ +static CFunFactHelper g_##funfactId##_Helper( CreateFunFact_##funfactId ); + + +//============================================================================= +// Per-team evaluation Fun Fact +//============================================================================= + +typedef bool (*TeamEvalFunction)(int iTeam, int &data1, int &data2, int &data3); + +class CFunFact_TeamEvalFunction : public FunFactEvaluator +{ +public: + CFunFact_TeamEvalFunction(FunFactId id, const char* szLocalizationToken, float fCoolness, TeamEvalFunction pfnEval, int iTeam ) : + FunFactEvaluator(id, szLocalizationToken, fCoolness), + m_pfnEval(pfnEval), + m_team(iTeam) + {} + + virtual bool Evaluate( FunFactVector& results ) const + { + int iData1, iData2, iData3; + if ( m_pfnEval(m_team, iData1, iData2, iData3) ) + { + FunFact funfact; + funfact.id = GetId(); + funfact.szLocalizationToken = GetLocalizationToken(); + funfact.fMagnitude = 0.0f; + results.AddToTail(funfact); + return true; + } + return false; + } + +private: + TeamEvalFunction m_pfnEval; + int m_team; +}; +#define DECLARE_FUNFACT_TEAMFUNC(funfactId, szLocalizationToken, fCoolness, pfnEval, iTeam) \ +static FunFactEvaluator *CreateFunFact_##funfactId( void ) \ +{ \ + return new CFunFact_TeamEvalFunction(funfactId, szLocalizationToken, fCoolness, pfnEval, iTeam);\ +}; \ +static CFunFactHelper g_##funfactId##_Helper( CreateFunFact_##funfactId ); + + +//============================================================================= +// High Stat-based Fun Fact +// This fun fact will find the player with the highest value for a particular +// stat, and validate when that stat exceeds a specified minimum +//============================================================================= +class CFunFact_StatBest : public FunFactEvaluator +{ +public: + CFunFact_StatBest(FunFactId id, const char* szLocalizationToken, float fCoolness, CSStatType_t statId, int iMin, int flags ) : + FunFactEvaluator(id, szLocalizationToken, fCoolness), + m_statId(statId), + m_min(iMin), + m_flags(flags) + { + V_strncpy(m_singularLocalizationToken, szLocalizationToken, sizeof(m_singularLocalizationToken)); + if (m_min == 1) + { + V_strncat(m_singularLocalizationToken, "_singular", sizeof(m_singularLocalizationToken)); + } + } + + virtual bool Evaluate( FunFactVector& results ) const + { + int iBestValue = 0; + int iBestPlayer = 0; + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer *pPlayer = UTIL_PlayerByIndex( i ); + if ( pPlayer ) + { + if (!PlayerQualifies(pPlayer, m_flags)) + continue; + + int iValue = CCS_GameStats.FindPlayerStats(pPlayer).statsCurrentRound[m_statId]; + if ( iValue > iBestValue ) + { + iBestValue = iValue; + iBestPlayer = i; + } + } + } + if ( iBestValue >= m_min ) + { + FunFact funfact; + funfact.id = GetId(); + funfact.szLocalizationToken = iBestValue == 1 ? m_singularLocalizationToken : GetLocalizationToken(); + funfact.iPlayer = iBestPlayer; + funfact.iData1 = iBestValue; + funfact.fMagnitude = 1.0f - ((float)m_min / iBestValue); + + results.AddToTail(funfact); + return true; + } + return false; + } + +private: + CSStatType_t m_statId; + int m_min; + char m_singularLocalizationToken[128]; + int m_flags; + +}; +#define DECLARE_FUNFACT_STATBEST(funfactId, szLocalizationToken, fCoolness, statId, iMin, flags) \ +static FunFactEvaluator *CreateFunFact_##funfactId( void ) \ +{ \ + return new CFunFact_StatBest(funfactId, szLocalizationToken, fCoolness, statId, iMin, flags); \ +}; \ +static CFunFactHelper g_##funfactId##_Helper( CreateFunFact_##funfactId ); + + +//============================================================================= +// Sum-based Fun Fact +// This fun fact will add up a stat for all players, and is valid when the +// sum exceeds a threshold +//============================================================================= +class CFunFact_StatSum : public FunFactEvaluator +{ +public: + CFunFact_StatSum(FunFactId id, const char* szLocalizationToken, float fCoolness, CSStatType_t statId, int iMin, EvalFlags::Type flags ) : + FunFactEvaluator(id, szLocalizationToken, fCoolness), + m_statId(statId), + m_min(iMin), + m_flags(flags) + {} + + virtual bool Evaluate( FunFactVector& results ) const + { + int iSum = 0; + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer *pPlayer = UTIL_PlayerByIndex( i ); + if ( pPlayer ) + { + if (!PlayerQualifies(pPlayer, m_flags)) + continue; + + iSum += CCS_GameStats.FindPlayerStats(pPlayer).statsCurrentRound[m_statId]; + } + } + if ( iSum >= m_min ) + { + FunFact funfact; + funfact.id = GetId(); + funfact.szLocalizationToken = GetLocalizationToken(); + funfact.iPlayer = 0; + funfact.iData1 = iSum; + funfact.fMagnitude = 1.0f - ((float)m_min / iSum); + + results.AddToTail(funfact); + return true; + } + return false; + } + +private: + CSStatType_t m_statId; + int m_min; + int m_flags; + +}; +#define DECLARE_FUNFACT_STATSUM(funfactId, szLocalizationToken, fCoolness, statId, iMin, flags) \ +static FunFactEvaluator *CreateFunFact_##funfactId( void ) \ +{ \ + return new CFunFact_StatSum(funfactId, szLocalizationToken, fCoolness, statId, iMin, flags); \ +}; \ +static CFunFactHelper g_##funfactId##_Helper( CreateFunFact_##funfactId ); + + + +//============================================================================= +// Helper function to calculate team accuracy +//============================================================================= + +float GetTeamAccuracy( int teamNumber ) +{ + int teamShots = 0; + int teamHits = 0; + + //Add up hits and shots + CBasePlayer *pPlayer = NULL; + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + pPlayer = UTIL_PlayerByIndex( i ); + if (pPlayer) + { + if (pPlayer->GetTeamNumber() == teamNumber) + { + teamShots += CCS_GameStats.FindPlayerStats(pPlayer).statsCurrentRound[CSSTAT_SHOTS_FIRED];; + teamHits += CCS_GameStats.FindPlayerStats(pPlayer).statsCurrentRound[CSSTAT_SHOTS_HIT];; + } + } + } + + if (teamShots > MIN_SHOTS_FOR_ACCURACY) + return (float)teamHits / teamShots; + + return 0.0f; +} + + + +//============================================================================= +// fun fact explicit evaluation functions +//============================================================================= + +bool FFEVAL_ALWAYS_TRUE( int &iPlayer, int &data1, int &data2, int &data3 ) +{ + return true; +} + +bool FFEVAL_CT_WIN_NO_KILLS( int &iPlayer, int &data1, int &data2, int &data3 ) +{ + return ( CSGameRules()->m_iRoundWinStatus == WINNER_CT && CSGameRules()->m_bNoTerroristsKilled ); +} + +bool FFEVAL_T_WIN_NO_KILLS( int &iPlayer, int &data1, int &data2, int &data3 ) +{ + return ( CSGameRules()->m_iRoundWinStatus == WINNER_TER && CSGameRules()->m_bNoCTsKilled ); +} + +bool FFEVAL_T_WIN_NO_CASUALTIES( int &iPlayer, int &data1, int &data2, int &data3 ) +{ + return ( CSGameRules()->m_iRoundWinStatus == WINNER_TER && CSGameRules()->m_bNoTerroristsKilled ); +} + +bool FFEVAL_CT_WIN_NO_CASUALTIES( int &iPlayer, int &data1, int &data2, int &data3 ) +{ + return ( CSGameRules()->m_iRoundWinStatus == WINNER_CT && CSGameRules()->m_bNoCTsKilled ); +} + +int FFEVAL_KILLED_DEFUSER( CCSPlayer* pPlayer ) +{ + return pPlayer->GetKilledDefuser() ? 1 : 0; +} + +int FFEVAL_KILLED_RESCUER( CCSPlayer* pPlayer ) +{ + return pPlayer->GetKilledRescuer() ? 1 : 0; +} + +int FFEVAL_KILLS_WITH_GRENADE( CCSPlayer* pPlayer ) +{ + return pPlayer->GetMaxGrenadeKills(); +} + +int FFEVAL_DAMAGE_NO_KILLS( CCSPlayer* pPlayer ) +{ + if (CCS_GameStats.FindPlayerStats(pPlayer).statsCurrentRound[CSSTAT_KILLS] == 0) + return CCS_GameStats.FindPlayerStats(pPlayer).statsCurrentRound[CSSTAT_DAMAGE]; + else + return 0; +} + +int FFEVAL_FIRST_KILL( CCSPlayer* pPlayer ) +{ + if ( pPlayer == CSGameRules()->m_pFirstKill && CSGameRules()->m_firstKillTime < FIRST_KILL_TIME ) + return CSGameRules()->m_firstKillTime; + else + return 0; +} + +int FFEVAL_FIRST_BLOOD( CCSPlayer* pPlayer ) +{ + if ( pPlayer == CSGameRules()->m_pFirstBlood && CSGameRules()->m_firstBloodTime < FIRST_BLOOD_TIME ) + return CSGameRules()->m_firstBloodTime; + else + return 0; +} + +bool FFEVAL_SHORT_ROUND( int &iPlayer, int &data1, int &data2, int &data3 ) +{ + if ( CSGameRules()->GetRoundLength() - CSGameRules()->GetRoundRemainingTime() < SHORT_ROUND_TIME ) + { + data1 = CSGameRules()->GetRoundLength() - CSGameRules()->GetRoundRemainingTime(); + return true; + } + return false; +} + +int FFEVAL_ACCURACY( CCSPlayer* pPlayer ) +{ + float shots = CCS_GameStats.FindPlayerStats(pPlayer).statsCurrentRound[CSSTAT_SHOTS_FIRED]; + float hits = CCS_GameStats.FindPlayerStats(pPlayer).statsCurrentRound[CSSTAT_SHOTS_HIT]; + if (shots >= MIN_SHOTS_FOR_ACCURACY) + return RoundFloatToInt(100.0f * hits / shots); + return 0; +} + +int FFEVAL_KILLED_HALF_OF_ENEMIES( CCSPlayer* pPlayer ) +{ + return pPlayer->GetPercentageOfEnemyTeamKilled(); +} + +bool FFEVAL_WON_AS_LAST_MEMBER( int &iPlayer, int &data1, int &data2, int &data3 ) +{ + CCSPlayer *pCSPlayer = NULL; + int winningTeam = CSGameRules()->m_iRoundWinStatus; + + if (winningTeam != TEAM_TERRORIST && winningTeam != TEAM_CT) + { + return false; + } + + int losingTeam = (winningTeam == TEAM_TERRORIST) ? TEAM_CT : TEAM_TERRORIST; + + CCSGameRules::TeamPlayerCounts playerCounts[TEAM_MAXCOUNT]; + CSGameRules()->GetPlayerCounts(playerCounts); + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + pCSPlayer = ToCSPlayer(UTIL_PlayerByIndex( i ) ); + if( pCSPlayer && pCSPlayer->GetTeamNumber() == winningTeam && pCSPlayer->IsAlive()) + { + //Check if the player is still the only living member of his team ( on the off chance that a player joins late) + //This check is a little hacky. We make sure that there are no enemies alive. Since the bomb causes the round to end before exploding, + //the only way for only 1 person to be alive at round win time is extermination or defuse (in both cases, the last living player caused the win) + if (playerCounts[winningTeam].totalAlivePlayers == 1 && playerCounts[losingTeam].totalAlivePlayers == 0) + { + const PlayerStats_t& playerStats = CCS_GameStats.FindPlayerStats( pCSPlayer ); + iPlayer = i; + data1 = playerStats.statsCurrentRound[CSSTAT_KILLS_WHILE_LAST_PLAYER_ALIVE]; + if (data1 >= 2) + { + return true; + } + } + } + } + + return false; +} + +int FFEVAL_KNIFE_IN_GUNFIGHT( CCSPlayer* pPlayer ) +{ + return pPlayer->WasWieldingKnifeAndKilledByGun() ? 1 : 0; +} + +int FFEVAL_MULTIPLE_ATTACKER_COUNT( CCSPlayer* pPlayer ) +{ + return pPlayer->GetNumEnemyDamagers(); +} + +int FFEVAL_USED_ALL_AMMO( CCSPlayer* pPlayer ) +{ + CWeaponCSBase *pRifleWeapon = dynamic_cast< CWeaponCSBase * >(pPlayer->Weapon_GetSlot( WEAPON_SLOT_RIFLE )); + CWeaponCSBase *pHandgunWeapon = dynamic_cast< CWeaponCSBase * >(pPlayer->Weapon_GetSlot( WEAPON_SLOT_PISTOL )); + if ( pRifleWeapon && !pRifleWeapon->HasAmmo() && pHandgunWeapon && !pHandgunWeapon->HasAmmo() ) + return 1; + else + return 0; +} + +int FFEVAL_DAMAGE_MULTIPLE_ENEMIES( CCSPlayer* pPlayer ) +{ + return pPlayer->GetNumEnemiesDamaged(); +} + +int FFEVAL_USED_MULTIPLE_WEAPONS( CCSPlayer* pPlayer ) +{ + return pPlayer->GetNumFirearmsUsed(); +} + +int FFEVAL_DEFUSED_WITH_DROPPED_KIT( CCSPlayer* pPlayer ) +{ + return pPlayer->GetDefusedWithPickedUpKit() ? 1 : 0; +} + +bool FFEVAL_TERRORIST_ACCURACY( int &iPlayer, int &data1, int &data2, int &data3 ) +{ + float terroristAccuracy = GetTeamAccuracy(TEAM_TERRORIST); + float ctAccuracy = GetTeamAccuracy(TEAM_CT); + + if (terroristAccuracy > 0.2f && terroristAccuracy > ctAccuracy) + { + data1 = RoundFloatToInt(terroristAccuracy * 100.0f); + return true; + } + return false; +} + +bool FFEVAL_CT_ACCURACY( int &iPlayer, int &data1, int &data2, int &data3 ) +{ + float terroristAccuracy = GetTeamAccuracy(TEAM_TERRORIST); + float ctAccuracy = GetTeamAccuracy(TEAM_CT); + + if (ctAccuracy > 0.2f && ctAccuracy > terroristAccuracy) + { + data1 = RoundFloatToInt(ctAccuracy * 100.0f); + return true; + } + return false; +} + +bool FFEVAL_SAME_UNIFORM( int iTeam, int &iData1, int &iData2, int &iData3 ) +{ + int numberInUniform = 0; + int iUniform = -1; + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CCSPlayer *pCSPlayer = ToCSPlayer(UTIL_PlayerByIndex( i ) ); + if ( pCSPlayer && pCSPlayer->GetTeamNumber() == iTeam && pCSPlayer->State_Get() != STATE_PICKINGCLASS) + { + if (iUniform == -1) + { + iUniform = pCSPlayer->PlayerClass(); + } + else if (pCSPlayer->PlayerClass() != iUniform) + { + return false; + } + ++numberInUniform; + } + } + + return numberInUniform >= 3; +} + +bool FFEVAL_BEST_TERRORIST_ACCURACY( int &iPlayer, int &data1, int &data2, int &data3 ) +{ + float fAccuracy = 0.0f, fBestAccuracy = 0.0f; + CBasePlayer *pPlayer = NULL; + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + pPlayer = UTIL_PlayerByIndex( i ); + + // Look only at terrorist players + if ( pPlayer && pPlayer->GetTeamNumber() == TEAM_TERRORIST ) + { + // Calculate accuracy the terrorist + float shots = CCS_GameStats.FindPlayerStats(pPlayer).statsCurrentRound[CSSTAT_SHOTS_FIRED]; + float hits = CCS_GameStats.FindPlayerStats(pPlayer).statsCurrentRound[CSSTAT_SHOTS_HIT]; + if (shots > MIN_SHOTS_FOR_ACCURACY) + { + fAccuracy = (float)hits / shots; + } + + // Track the most accurate terrorist + if ( fAccuracy > fBestAccuracy ) + { + fBestAccuracy = fAccuracy; + iPlayer = i; + } + } + } + + if ( fBestAccuracy - GetTeamAccuracy( TEAM_TERRORIST ) >= 0.10f ) + { + data1 = RoundFloatToInt(fBestAccuracy * 100.0f); + data2 = RoundFloatToInt(GetTeamAccuracy( TEAM_TERRORIST ) * 100.0f); + return true; + } + + return false; +} + +bool FFEVAL_BEST_COUNTERTERRORIST_ACCURACY( int &iPlayer, int &data1, int &data2, int &data3 ) +{ + float fAccuracy = 0.0f, fBestAccuracy = 0.0f; + CBasePlayer *pPlayer = NULL; + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + pPlayer = UTIL_PlayerByIndex( i ); + + // Look only at counter-terrorist players + if ( pPlayer && pPlayer->GetTeamNumber() == TEAM_CT ) + { + // Calculate accuracy the counter-terrorist + float shots = CCS_GameStats.FindPlayerStats(pPlayer).statsCurrentRound[CSSTAT_SHOTS_FIRED]; + float hits = CCS_GameStats.FindPlayerStats(pPlayer).statsCurrentRound[CSSTAT_SHOTS_HIT]; + if (shots > MIN_SHOTS_FOR_ACCURACY) + { + fAccuracy = (float)hits / shots; + } + + // Track the most accurate counter-terrorist + if ( fAccuracy > fBestAccuracy ) + { + fBestAccuracy = fAccuracy; + iPlayer = i; + } + } + } + + if ( fBestAccuracy - GetTeamAccuracy( TEAM_CT ) >= 0.10f ) + { + data1 = RoundFloatToInt(fBestAccuracy * 100.0f); + data2 = RoundFloatToInt(GetTeamAccuracy( TEAM_CT ) * 100.0f); + return true; + } + + return false; +} + + +//============================================================================= +// Fun Fact Declarations +//============================================================================= + +DECLARE_FUNFACT_STATBEST( FUNFACT_DAMAGE_WITH_GRENADES, "#funfact_damage_with_grenade", 0.5f, CSSTAT_GRENADE_DAMAGE, 200, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_KNIFE_KILLS, "#funfact_knife_kills", 0.5f, CSSTAT_KILLS_KNIFE, 1, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_KILLS_WITH_GRENADES, "#funfact_kills_grenades", 0.7f, CSSTAT_KILLS_HEGRENADE, 2, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_BLIND_KILLS, "#funfact_blind_kills", 0.9f, CSSTAT_KILLS_WHILE_BLINDED, 1, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_KILLED_ENEMIES, "#funfact_killed_enemies", 0.6f, CSSTAT_KILLS, 3, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_KILLS_WITH_LAST_ROUND, "#funfact_kills_with_last_round", 0.6f, CSSTAT_KILLS_WITH_LAST_ROUND, 1, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_DONATED_WEAPONS, "#funfact_donated_weapons", 0.3f, CSSTAT_WEAPONS_DONATED, 2, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_NUM_TIMES_JUMPED, "#funfact_num_times_jumped", 0.2f, CSSTAT_TOTAL_JUMPS, 10, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_FALL_DAMAGE, "#funfact_fall_damage", 0.2f, CSSTAT_FALL_DAMAGE, 50, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_POSTHUMOUS_KILLS_WITH_GRENADE, "#funfact_posthumous_kills_with_grenade", 1.0f, CSSTAT_GRENADE_POSTHUMOUSKILLS, 1, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_ITEMS_PURCHASED, "#funfact_items_purchased", 0.2f, CSSTAT_ITEMS_PURCHASED, 5, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_NUMBER_OF_OVERKILLS, "#funfact_number_of_overkills", 0.5f, CSSTAT_DOMINATION_OVERKILLS, 2, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_MONEY_SPENT, "#funfact_money_spent", 0.2f, CSSTAT_MONEY_SPENT, 5000, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_GRENADES_THROWN, "#funfact_grenades_thrown", 0.3f, CSSTAT_GRENADES_THROWN, 2, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_DEFENDED_BOMB, "#funfact_defended_bomb", 0.5f, CSSTAT_KILLS_WHILE_DEFENDING_BOMB, 2, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_ITEMS_DROPPED_VALUE, "#funfact_items_dropped_value", 0.5f, CSTAT_ITEMS_DROPPED_VALUE, 10000, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_KILL_WOUNDED_ENEMIES, "#funfact_kill_wounded_enemies", 0.4f, CSSTAT_KILLS_ENEMY_WOUNDED, 3, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_KILLS_HEADSHOTS, "#funfact_kills_headshots", 0.7f, CSSTAT_KILLS_HEADSHOT, 3, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_BROKE_WINDOWS, "#funfact_broke_windows", 0.3f, CSSTAT_NUM_BROKEN_WINDOWS, 5, EvalFlags::HighestOnly); +DECLARE_FUNFACT_STATBEST( FUNFACT_NIGHTVISION_DAMAGE, "#funfact_nightvision_damage", 0.5f, CSSTAT_NIGHTVISION_DAMAGE, 100, EvalFlags::HighestOnly); + +DECLARE_FUNFACT_STATSUM( FUNFACT_SHOTS_FIRED, "#funfact_shots_fired", 0.1f, CSSTAT_SHOTS_FIRED, 200, EvalFlags::All); + +DECLARE_FUNFACT_PLAYERFUNC( FUNFACT_KILL_DEFUSER, "#funfact_kill_defuser", 0.6f, FFEVAL_KILLED_DEFUSER, 1, EvalFlags::TeamTerrorist | EvalFlags::WinningTeam); +DECLARE_FUNFACT_PLAYERFUNC( FUNFACT_KILL_RESCUER, "#funfact_kill_rescuer", 0.6f, FFEVAL_KILLED_RESCUER, 1, EvalFlags::TeamTerrorist); +DECLARE_FUNFACT_PLAYERFUNC( FUNFACT_KILLS_WITH_SINGLE_GRENADE, "#funfact_kills_with_single_grenade", 0.8f, FFEVAL_KILLS_WITH_GRENADE, 2, EvalFlags::HighestOnly); +DECLARE_FUNFACT_PLAYERFUNC( FUNFACT_DAMAGE_NO_KILLS, "#funfact_damage_no_kills", 0.4f, FFEVAL_DAMAGE_NO_KILLS, 200, EvalFlags::HighestOnly); +DECLARE_FUNFACT_PLAYERFUNC( FUNFACT_FIRST_KILL, "#funfact_first_kill", 0.2f, FFEVAL_FIRST_KILL, 1, EvalFlags::HighestOnly); +DECLARE_FUNFACT_PLAYERFUNC( FUNFACT_FIRST_BLOOD, "#funfact_first_blood", 0.2f, FFEVAL_FIRST_BLOOD, 1, EvalFlags::HighestOnly); +DECLARE_FUNFACT_PLAYERFUNC( FUNFACT_BEST_ACCURACY, "#funfact_best_accuracy", 0.4f, FFEVAL_ACCURACY, 20, EvalFlags::HighestOnly); +DECLARE_FUNFACT_PLAYERFUNC( FUNFACT_KNIFE_IN_GUNFIGHT, "#funfact_knife_in_gunfight", 0.6f, FFEVAL_KNIFE_IN_GUNFIGHT , 1, EvalFlags::All); +DECLARE_FUNFACT_PLAYERFUNC( FUNFACT_SURVIVED_MULTIPLE_ATTACKERS, "#funfact_survived_multiple_attackers", 0.3f, FFEVAL_MULTIPLE_ATTACKER_COUNT, 3, EvalFlags::HighestOnly | EvalFlags::Alive); +DECLARE_FUNFACT_PLAYERFUNC( FUNFACT_DIED_FROM_MULTIPLE_ATTACKERS, "#funfact_died_from_multiple_attackers", 0.5f, FFEVAL_MULTIPLE_ATTACKER_COUNT, 3, EvalFlags::HighestOnly | EvalFlags::Dead); +DECLARE_FUNFACT_PLAYERFUNC( FUNFACT_USED_ALL_AMMO, "#funfact_used_all_ammo", 0.5f, FFEVAL_USED_ALL_AMMO, 1, EvalFlags::All ); +DECLARE_FUNFACT_PLAYERFUNC( FUNFACT_DAMAGE_MULTIPLE_ENEMIES, "#funfact_damage_multiple_enemies", 0.5f, FFEVAL_DAMAGE_MULTIPLE_ENEMIES, 3, EvalFlags::HighestOnly); +DECLARE_FUNFACT_PLAYERFUNC( FUNFACT_USED_MULTIPLE_WEAPONS, "#funfact_used_multiple_weapons", 0.5f, FFEVAL_USED_MULTIPLE_WEAPONS, 4, EvalFlags::HighestOnly); +DECLARE_FUNFACT_PLAYERFUNC( FUNFACT_DEFUSED_WITH_DROPPED_KIT, "#funfact_defused_with_dropped_kit", 0.4f, FFEVAL_DEFUSED_WITH_DROPPED_KIT, 1, EvalFlags::TeamCT); +DECLARE_FUNFACT_PLAYERFUNC( FUNFACT_KILLED_HALF_OF_ENEMIES, "#funfact_killed_half_of_enemies", 0.5f, FFEVAL_KILLED_HALF_OF_ENEMIES, 50, EvalFlags::WinningTeam | EvalFlags::HighestOnly); + +DECLARE_FUNFACT_EVALFUNC( FUNFACT_CT_WIN_NO_KILLS, "#funfact_ct_win_no_kills", 0.4f, FFEVAL_CT_WIN_NO_KILLS); +DECLARE_FUNFACT_EVALFUNC( FUNFACT_T_WIN_NO_KILLS, "#funfact_t_win_no_kills", 0.4f, FFEVAL_T_WIN_NO_KILLS ); +DECLARE_FUNFACT_EVALFUNC( FUNFACT_T_WIN_NO_CASUALTIES, "#funfact_t_win_no_casualties", 0.2f, FFEVAL_T_WIN_NO_CASUALTIES ); +DECLARE_FUNFACT_EVALFUNC( FUNFACT_CT_WIN_NO_CASUALTIES, "#funfact_ct_win_no_casualties", 0.2f, FFEVAL_CT_WIN_NO_CASUALTIES ); +DECLARE_FUNFACT_EVALFUNC( FUNFACT_SHORT_ROUND, "#funfact_short_round", 0.3f, FFEVAL_SHORT_ROUND ); +DECLARE_FUNFACT_EVALFUNC( FUNFACT_WON_AS_LAST_MEMBER, "#funfact_won_as_last_member", 0.6f, FFEVAL_WON_AS_LAST_MEMBER ); +DECLARE_FUNFACT_EVALFUNC( FUNFACT_TERRORIST_ACCURACY, "#funfact_terrorist_accuracy", 0.2f, FFEVAL_TERRORIST_ACCURACY); +DECLARE_FUNFACT_EVALFUNC( FUNFACT_CT_ACCURACY, "#funfact_ct_accuracy", 0.2f, FFEVAL_CT_ACCURACY); +DECLARE_FUNFACT_EVALFUNC( FUNFACT_BEST_TERRORIST_ACCURACY, "#funfact_best_terrorist_accuracy", 0.3f, FFEVAL_BEST_TERRORIST_ACCURACY); +DECLARE_FUNFACT_EVALFUNC( FUNFACT_BEST_COUNTERTERRORIST_ACCURACY, "#funfact_best_counterterrorist_accuracy", 0.3f, FFEVAL_BEST_COUNTERTERRORIST_ACCURACY); +DECLARE_FUNFACT_EVALFUNC( FUNFACT_FALLBACK1, "#funfact_fallback1", 0.0f, FFEVAL_ALWAYS_TRUE); +DECLARE_FUNFACT_EVALFUNC( FUNFACT_FALLBACK2, "#funfact_fallback2", 0.0f, FFEVAL_ALWAYS_TRUE); + +DECLARE_FUNFACT_TEAMFUNC( FUNFACT_SAME_UNIFORM_TERRORIST, "#funfact_same_uniform_terrorist", 0.5f, FFEVAL_SAME_UNIFORM, TEAM_TERRORIST); +DECLARE_FUNFACT_TEAMFUNC( FUNFACT_SAME_UNIFORM_CT, "#funfact_same_uniform_ct", 0.5f, FFEVAL_SAME_UNIFORM, TEAM_CT); |