You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
204 lines
5.6 KiB
204 lines
5.6 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
#include "cbase.h" |
|
#include "usermessages.h" |
|
#include "funfactmgr_cs.h" |
|
|
|
const float kCooldownRatePlayer = 0.4f; |
|
const float kCooldownRateFunFact = 0.2f; |
|
|
|
const float kWeightPlayerCooldown = 0.8f; |
|
const float kWeightFunFactCooldown = 1.0f; |
|
const float kWeightCoolness = 2.0f; |
|
const float kWeightRarity = 1.0f; |
|
|
|
#define DEBUG_FUNFACT_SCORING 0 |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: constructor |
|
//----------------------------------------------------------------------------- |
|
CCSFunFactMgr::CCSFunFactMgr() : |
|
CAutoGameSystemPerFrame( "CCSFunFactMgr" ), |
|
m_funFactDatabase(0, 100, DefLessFunc(int) ) |
|
{ |
|
for ( int i = 0; i < MAX_PLAYERS; ++i ) |
|
{ |
|
m_playerCooldown[i] = 0.0f; |
|
} |
|
} |
|
|
|
CCSFunFactMgr::~CCSFunFactMgr() |
|
{ |
|
Shutdown(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Initializes the fun fact manager |
|
//----------------------------------------------------------------------------- |
|
bool CCSFunFactMgr::Init() |
|
{ |
|
ListenForGameEvent( "player_connect" ); |
|
|
|
CFunFactHelper *pFunFactHelper = CFunFactHelper::s_pFirst; |
|
|
|
// create database of all fun fact evaluators (and initial usage metrics) |
|
while ( pFunFactHelper ) |
|
{ |
|
FunFactDatabaseEntry entry; |
|
entry.fCooldown = 0.0f; |
|
entry.iOccurrences = 0; |
|
entry.pEvaluator = pFunFactHelper->m_pfnCreate(); |
|
m_funFactDatabase.Insert(entry.pEvaluator->GetId(), entry); |
|
|
|
pFunFactHelper = pFunFactHelper->m_pNext; |
|
} |
|
|
|
for (int i = 0; i < ARRAYSIZE(m_playerCooldown); ++i) |
|
{ |
|
m_playerCooldown[i] = 0.0f; |
|
} |
|
|
|
m_numRounds = 0; |
|
|
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Shuts down the fun fact manager |
|
//----------------------------------------------------------------------------- |
|
void CCSFunFactMgr::Shutdown() |
|
{ |
|
FOR_EACH_MAP( m_funFactDatabase, iter ) |
|
{ |
|
delete m_funFactDatabase[iter].pEvaluator; |
|
} |
|
m_funFactDatabase.RemoveAll(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Per frame processing |
|
//----------------------------------------------------------------------------- |
|
void CCSFunFactMgr::Update( float frametime ) |
|
{ |
|
|
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Listens for game events. Clears out map based stats and player based stats when necessary |
|
//----------------------------------------------------------------------------- |
|
void CCSFunFactMgr::FireGameEvent( IGameEvent *event ) |
|
{ |
|
const char *eventname = event->GetName(); |
|
|
|
if ( Q_strcmp( "player_connect", eventname ) == 0 ) |
|
{ |
|
int index = event->GetInt("index");// player slot (entity index-1) |
|
ASSERT( index >= 0 && index < MAX_PLAYERS ); |
|
if( index >= 0 && index < MAX_PLAYERS ) |
|
{ |
|
m_playerCooldown[index] = 0.0f; |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Finds the best fun fact to display and returns all necessary information through the parameters |
|
//----------------------------------------------------------------------------- |
|
bool CCSFunFactMgr::GetRoundEndFunFact( int iWinningTeam, int iRoundResult, FunFact& funfact ) |
|
{ |
|
FunFactVector validFunFacts; |
|
|
|
// Generate a vector of all valid fun facts for this round |
|
FOR_EACH_MAP( m_funFactDatabase, i ) |
|
{ |
|
FunFact funFact; |
|
if ( m_funFactDatabase[i].pEvaluator->Evaluate(validFunFacts) ) |
|
{ |
|
m_funFactDatabase[i].iOccurrences++; |
|
} |
|
} |
|
|
|
m_numRounds++; |
|
|
|
if (validFunFacts.Size() == 0) |
|
return false; |
|
|
|
// pick the fun fact with the highest score |
|
float fBestScore = -FLT_MAX; |
|
int iFunFactIndex = -1; |
|
|
|
#if DEBUG_FUNFACT_SCORING |
|
Msg("Scoring fun facts:\n"); |
|
#endif |
|
|
|
FOR_EACH_VEC(validFunFacts, i) |
|
{ |
|
float fScore = ScoreFunFact(validFunFacts[i]); |
|
|
|
#if DEBUG_FUNFACT_SCORING |
|
char szPlayerName[64]; |
|
const FunFact& funfact = validFunFacts[i]; |
|
if (funfact.iPlayer > 0) |
|
V_strncpy(szPlayerName, ToCSPlayer(UTIL_PlayerByIndex(funfact.iPlayer))->GetPlayerName(), sizeof(szPlayerName)); |
|
else |
|
V_strcpy(szPlayerName, ""); |
|
|
|
Msg("(%5.4f) %s, %s, %i, %i, %i\n", fScore, funfact.szLocalizationToken, szPlayerName, funfact.iData1, funfact.iData2, funfact.iData3); |
|
#endif |
|
|
|
if (fScore > fBestScore) |
|
{ |
|
fBestScore = fScore; |
|
iFunFactIndex = i; |
|
} |
|
} |
|
|
|
if (iFunFactIndex < 0) |
|
return false; |
|
|
|
funfact = validFunFacts[iFunFactIndex]; |
|
|
|
// decay player cooldowns |
|
for (int i = 0; i < MAX_PLAYERS; ++i ) |
|
{ |
|
m_playerCooldown[i] *= (1.0f - kCooldownRatePlayer); |
|
} |
|
|
|
// decay funfact cooldowns |
|
FOR_EACH_MAP(m_funFactDatabase, i) |
|
{ |
|
m_funFactDatabase[i].fCooldown *= (1.0f - kCooldownRateFunFact); |
|
} |
|
|
|
// set player cooldown for player in funfact |
|
if ( funfact.iPlayer ) |
|
{ |
|
m_playerCooldown[funfact.iPlayer - 1] = 1.0f; |
|
} |
|
|
|
// set funfact cooldown for current funfact |
|
m_funFactDatabase[m_funFactDatabase.Find(funfact.id)].fCooldown = 1.0f; |
|
|
|
return true; |
|
} |
|
|
|
float CCSFunFactMgr::ScoreFunFact( const FunFact& funfact ) |
|
{ |
|
float fScore = 0.0f; |
|
const FunFactDatabaseEntry& dbEntry = m_funFactDatabase[m_funFactDatabase.Find(funfact.id)]; |
|
|
|
// add the coolness score for the funfact |
|
fScore += kWeightCoolness * dbEntry.pEvaluator->GetCoolness() * (1.0f + funfact.fMagnitude); |
|
|
|
// subtract the cooldown for the funfact |
|
fScore -= kWeightFunFactCooldown * dbEntry.fCooldown; |
|
|
|
// subtract the cooldown for the player |
|
if ( funfact.iPlayer ) { |
|
fScore -= kWeightPlayerCooldown * m_playerCooldown[funfact.iPlayer - 1]; |
|
} |
|
|
|
// add the rarity bonus |
|
fScore += kWeightRarity * powf((1.0f - (float)dbEntry.iOccurrences / m_numRounds), 2.0f); |
|
|
|
return fScore; |
|
}
|
|
|