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.
210 lines
5.7 KiB
210 lines
5.7 KiB
#include "cbase.h"
|
|
#include "usermessages.h"
|
|
#include "funfactmgr_cs.h"
|
|
#include "cs_shareddefs.h"
|
|
|
|
const float kCooldownRatePlayer = 0.5f;
|
|
const float kCooldownRateFunFact = 0.2f;
|
|
|
|
const float kWeightPlayerCooldown = 0.7f;
|
|
const float kWeightFunFactCooldown = 1.0f;
|
|
const float kWeightCoolness = 1.2f;
|
|
const float kWeightRarity = 1.0f;
|
|
|
|
#define DEBUG_FUNFACT_SCORING 0
|
|
|
|
#if DEBUG_FUNFACT_SCORING
|
|
#include "cs_player.h"
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: constructor
|
|
//-----------------------------------------------------------------------------
|
|
CCSFunFactMgr::CCSFunFactMgr() :
|
|
CAutoGameSystemPerFrame( "CCSFunFactMgr" ),
|
|
m_funFactDatabase(0, 100, DefLessFunc(int) )
|
|
{
|
|
for ( int i = 0; i < ARRAYSIZE(m_playerCooldown); ++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, e_RoundEndReason iRoundResult, FunFact& funfact )
|
|
{
|
|
|
|
//No fun fact for surrender
|
|
if ( iRoundResult == CTs_Surrender || iRoundResult == Terrorists_Surrender )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
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(iRoundResult, validFunFacts) )
|
|
{
|
|
m_funFactDatabase[i].iOccurrences++;
|
|
}
|
|
}
|
|
|
|
m_numRounds++;
|
|
|
|
if (validFunFacts.Count() == 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 < ARRAYSIZE(m_playerCooldown); ++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
|
|
m_playerCooldown[funfact.iPlayer] = 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
|
|
fScore -= kWeightPlayerCooldown * m_playerCooldown[funfact.iPlayer];
|
|
|
|
// add the rarity bonus
|
|
fScore += kWeightRarity * powf((1.0f - (float)dbEntry.iOccurrences / m_numRounds), 4.0f);
|
|
|
|
return fScore;
|
|
}
|