Team Fortress 2 Source Code as on 22/4/2020
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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. #include "cbase.h"
  3. #include "usermessages.h"
  4. #include "funfactmgr_cs.h"
  5. const float kCooldownRatePlayer = 0.4f;
  6. const float kCooldownRateFunFact = 0.2f;
  7. const float kWeightPlayerCooldown = 0.8f;
  8. const float kWeightFunFactCooldown = 1.0f;
  9. const float kWeightCoolness = 2.0f;
  10. const float kWeightRarity = 1.0f;
  11. #define DEBUG_FUNFACT_SCORING 0
  12. //-----------------------------------------------------------------------------
  13. // Purpose: constructor
  14. //-----------------------------------------------------------------------------
  15. CCSFunFactMgr::CCSFunFactMgr() :
  16. CAutoGameSystemPerFrame( "CCSFunFactMgr" ),
  17. m_funFactDatabase(0, 100, DefLessFunc(int) )
  18. {
  19. for ( int i = 0; i < MAX_PLAYERS; ++i )
  20. {
  21. m_playerCooldown[i] = 0.0f;
  22. }
  23. }
  24. CCSFunFactMgr::~CCSFunFactMgr()
  25. {
  26. Shutdown();
  27. }
  28. //-----------------------------------------------------------------------------
  29. // Purpose: Initializes the fun fact manager
  30. //-----------------------------------------------------------------------------
  31. bool CCSFunFactMgr::Init()
  32. {
  33. ListenForGameEvent( "player_connect" );
  34. CFunFactHelper *pFunFactHelper = CFunFactHelper::s_pFirst;
  35. // create database of all fun fact evaluators (and initial usage metrics)
  36. while ( pFunFactHelper )
  37. {
  38. FunFactDatabaseEntry entry;
  39. entry.fCooldown = 0.0f;
  40. entry.iOccurrences = 0;
  41. entry.pEvaluator = pFunFactHelper->m_pfnCreate();
  42. m_funFactDatabase.Insert(entry.pEvaluator->GetId(), entry);
  43. pFunFactHelper = pFunFactHelper->m_pNext;
  44. }
  45. for (int i = 0; i < ARRAYSIZE(m_playerCooldown); ++i)
  46. {
  47. m_playerCooldown[i] = 0.0f;
  48. }
  49. m_numRounds = 0;
  50. return true;
  51. }
  52. //-----------------------------------------------------------------------------
  53. // Purpose: Shuts down the fun fact manager
  54. //-----------------------------------------------------------------------------
  55. void CCSFunFactMgr::Shutdown()
  56. {
  57. FOR_EACH_MAP( m_funFactDatabase, iter )
  58. {
  59. delete m_funFactDatabase[iter].pEvaluator;
  60. }
  61. m_funFactDatabase.RemoveAll();
  62. }
  63. //-----------------------------------------------------------------------------
  64. // Purpose: Per frame processing
  65. //-----------------------------------------------------------------------------
  66. void CCSFunFactMgr::Update( float frametime )
  67. {
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Purpose: Listens for game events. Clears out map based stats and player based stats when necessary
  71. //-----------------------------------------------------------------------------
  72. void CCSFunFactMgr::FireGameEvent( IGameEvent *event )
  73. {
  74. const char *eventname = event->GetName();
  75. if ( Q_strcmp( "player_connect", eventname ) == 0 )
  76. {
  77. int index = event->GetInt("index");// player slot (entity index-1)
  78. ASSERT( index >= 0 && index < MAX_PLAYERS );
  79. if( index >= 0 && index < MAX_PLAYERS )
  80. {
  81. m_playerCooldown[index] = 0.0f;
  82. }
  83. }
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Purpose: Finds the best fun fact to display and returns all necessary information through the parameters
  87. //-----------------------------------------------------------------------------
  88. bool CCSFunFactMgr::GetRoundEndFunFact( int iWinningTeam, int iRoundResult, FunFact& funfact )
  89. {
  90. FunFactVector validFunFacts;
  91. // Generate a vector of all valid fun facts for this round
  92. FOR_EACH_MAP( m_funFactDatabase, i )
  93. {
  94. FunFact funFact;
  95. if ( m_funFactDatabase[i].pEvaluator->Evaluate(validFunFacts) )
  96. {
  97. m_funFactDatabase[i].iOccurrences++;
  98. }
  99. }
  100. m_numRounds++;
  101. if (validFunFacts.Size() == 0)
  102. return false;
  103. // pick the fun fact with the highest score
  104. float fBestScore = -FLT_MAX;
  105. int iFunFactIndex = -1;
  106. #if DEBUG_FUNFACT_SCORING
  107. Msg("Scoring fun facts:\n");
  108. #endif
  109. FOR_EACH_VEC(validFunFacts, i)
  110. {
  111. float fScore = ScoreFunFact(validFunFacts[i]);
  112. #if DEBUG_FUNFACT_SCORING
  113. char szPlayerName[64];
  114. const FunFact& funfact = validFunFacts[i];
  115. if (funfact.iPlayer > 0)
  116. V_strncpy(szPlayerName, ToCSPlayer(UTIL_PlayerByIndex(funfact.iPlayer))->GetPlayerName(), sizeof(szPlayerName));
  117. else
  118. V_strcpy(szPlayerName, "");
  119. Msg("(%5.4f) %s, %s, %i, %i, %i\n", fScore, funfact.szLocalizationToken, szPlayerName, funfact.iData1, funfact.iData2, funfact.iData3);
  120. #endif
  121. if (fScore > fBestScore)
  122. {
  123. fBestScore = fScore;
  124. iFunFactIndex = i;
  125. }
  126. }
  127. if (iFunFactIndex < 0)
  128. return false;
  129. funfact = validFunFacts[iFunFactIndex];
  130. // decay player cooldowns
  131. for (int i = 0; i < MAX_PLAYERS; ++i )
  132. {
  133. m_playerCooldown[i] *= (1.0f - kCooldownRatePlayer);
  134. }
  135. // decay funfact cooldowns
  136. FOR_EACH_MAP(m_funFactDatabase, i)
  137. {
  138. m_funFactDatabase[i].fCooldown *= (1.0f - kCooldownRateFunFact);
  139. }
  140. // set player cooldown for player in funfact
  141. if ( funfact.iPlayer )
  142. {
  143. m_playerCooldown[funfact.iPlayer - 1] = 1.0f;
  144. }
  145. // set funfact cooldown for current funfact
  146. m_funFactDatabase[m_funFactDatabase.Find(funfact.id)].fCooldown = 1.0f;
  147. return true;
  148. }
  149. float CCSFunFactMgr::ScoreFunFact( const FunFact& funfact )
  150. {
  151. float fScore = 0.0f;
  152. const FunFactDatabaseEntry& dbEntry = m_funFactDatabase[m_funFactDatabase.Find(funfact.id)];
  153. // add the coolness score for the funfact
  154. fScore += kWeightCoolness * dbEntry.pEvaluator->GetCoolness() * (1.0f + funfact.fMagnitude);
  155. // subtract the cooldown for the funfact
  156. fScore -= kWeightFunFactCooldown * dbEntry.fCooldown;
  157. // subtract the cooldown for the player
  158. if ( funfact.iPlayer ) {
  159. fScore -= kWeightPlayerCooldown * m_playerCooldown[funfact.iPlayer - 1];
  160. }
  161. // add the rarity bonus
  162. fScore += kWeightRarity * powf((1.0f - (float)dbEntry.iOccurrences / m_numRounds), 2.0f);
  163. return fScore;
  164. }