Counter Strike : Global Offensive Source Code
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

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