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.

684 lines
27 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Display a list of achievements for the current game
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "stats_summary.h"
  8. #include "vgui_controls/Button.h"
  9. #include "vgui/ILocalize.h"
  10. #include "ixboxsystem.h"
  11. #include "iachievementmgr.h"
  12. #include "filesystem.h"
  13. #include "vgui_controls/ImagePanel.h"
  14. #include "vgui_controls/ComboBox.h"
  15. #include "vgui_controls/CheckButton.h"
  16. #include "vgui_controls/ImageList.h"
  17. #include "fmtstr.h"
  18. #include "c_cs_playerresource.h"
  19. #include "../../../public/steam/steam_api.h"
  20. #include "achievementmgr.h"
  21. #include "../../../../public/vgui/IScheme.h"
  22. #include "../vgui_controls/ScrollBar.h"
  23. #include "stat_card.h"
  24. #include "weapon_csbase.h"
  25. #include "cs_weapon_parse.h"
  26. #include "buy_presets/buy_presets.h"
  27. #include "win_panel_round.h"
  28. #include "cs_client_gamestats.h"
  29. #include "achievements_cs.h"
  30. #include "ienginevgui.h"
  31. #define STAT_NUM_ARRAY_LENGTH 8
  32. using namespace vgui;
  33. // memdbgon must be the last include file in a .cpp file!!!
  34. #include "tier0/memdbgon.h"
  35. #include <locale.h>
  36. extern CAchievementMgr g_AchievementMgrCS;
  37. const int maxRecentAchievementToDisplay = 10;
  38. /**
  39. * public ConvertNumberToMantissaSuffixForm()
  40. *
  41. * Convert a floating point number to a string form incorporating a mantissa and a magnitude suffix (such as "K" for thousands).
  42. *
  43. * Parameters:
  44. * fNum -
  45. * textBuffer - output buffer
  46. * textBufferLen - size of output buffer in characters
  47. * bTrimTrailingZeros - indicates whether to remove trailing zeros of numbers without suffixes (e.g., "32.00000" becomes "32")
  48. * iSignificantDigits - the desired number of significant digits in the result (e.g, "1.23" has 3 significant digits)
  49. *
  50. * Returns:
  51. * bool - true on success
  52. */
  53. bool ConvertNumberToMantissaSuffixForm(float fNum, wchar_t* textBuffer, int textBufferLen, bool bTrimTrailingZeros = true, int iSignificantDigits = 3)
  54. {
  55. // we need room for at least iSignificantDigits + 3 characters
  56. Assert(textBufferLen >= iSignificantDigits + 3);
  57. // find the correct power of 1000 exponent
  58. Assert(fNum >= 0.0f);
  59. int iExponent = 0;
  60. while (fNum >= powf(10.0f, iExponent + 3))
  61. {
  62. iExponent += 3;
  63. }
  64. // look in the localization table for the matching suffix; fallback to lower suffixes when necessary
  65. wchar_t *pSuffix = NULL;
  66. for (; iExponent > 0; iExponent -= 3)
  67. {
  68. char localizationToken[64];
  69. V_snprintf(localizationToken, sizeof(localizationToken), "#GameUI_NumSuffix_E%i", iExponent);
  70. pSuffix = g_pVGuiLocalize->Find(localizationToken);
  71. if (pSuffix != NULL)
  72. break;
  73. }
  74. V_snwprintf(textBuffer, textBufferLen, L"%f", fNum / powf(10.0f, iExponent));
  75. textBuffer[textBufferLen - 1] = L'\0';
  76. lconv* pLocaleSettings = localeconv();
  77. wchar_t decimalWChar = *pLocaleSettings->decimal_point;
  78. wchar_t* pDecimalPos = wcschr(textBuffer, decimalWChar);
  79. if (pDecimalPos == NULL)
  80. {
  81. Msg("ConvertNumberToMantissaSuffixForm(): decimal point not found in string %S for value %f\n", textBuffer, fNum);
  82. return false;
  83. }
  84. // trim trailing zeros
  85. int iNumCharsInBuffer = wcslen(textBuffer);
  86. if (pSuffix == NULL && bTrimTrailingZeros)
  87. {
  88. wchar_t* pLastChar;
  89. for (pLastChar = &textBuffer[iNumCharsInBuffer - 1]; pLastChar > pDecimalPos; --pLastChar)
  90. {
  91. if (*pLastChar != L'0') // note that this is checking for '0', not a NULL terminator
  92. break;
  93. *pLastChar = L'\0';
  94. }
  95. if (pLastChar == pDecimalPos)
  96. *pLastChar = L'\0';
  97. }
  98. // truncate the mantissa to the right of the decimal point so that it doesn't exceed the significant digits
  99. if (pDecimalPos != NULL && iNumCharsInBuffer > iSignificantDigits + 1)
  100. {
  101. if (pDecimalPos - &textBuffer[0] < iSignificantDigits)
  102. textBuffer[iSignificantDigits + 1] = L'\0'; // truncate at the correct number of significant digits
  103. else
  104. *pDecimalPos = L'\0'; // no room for any digits to the right of the decimal point, just truncate it at the "."
  105. }
  106. if (pSuffix != NULL)
  107. {
  108. #ifdef WIN32
  109. int retVal = V_snwprintf( textBuffer, textBufferLen, L"%s%s", textBuffer, pSuffix );
  110. #else
  111. int retVal = V_snwprintf( textBuffer, textBufferLen, L"%S%S", textBuffer, pSuffix );
  112. #endif
  113. if ( retVal < 0 )
  114. {
  115. Msg("ConvertNumberToMantissaSuffixForm(): unable to add suffix %S for value %f (buffer size was %i)\n", pSuffix, fNum, textBufferLen);
  116. return false;
  117. }
  118. }
  119. return true;
  120. }
  121. CStatsSummary::CStatsSummary(vgui::Panel *parent, const char *name) : BaseClass(parent, "CSAchievementsDialog"),
  122. m_StatImageMap(DefLessFunc(CSStatType_t))
  123. {
  124. m_iFixedWidth = 900; // Give this an initial value in order to set a proper size
  125. SetBounds(0, 0, 900, 780);
  126. SetMinimumSize(256, 780);
  127. m_pStatCard = new StatCard(this, "ignored");
  128. m_pImageList = NULL;
  129. m_iDefaultWeaponImage = -1;
  130. m_iDefaultMapImage = -1;
  131. m_pImagePanelFavWeapon = new ImagePanel(this, "FavoriteWeaponImage");
  132. m_pImagePanelLastMapFavWeapon = new ImagePanel(this, "FavWeaponIcon");
  133. m_pImagePanelFavMap = new ImagePanel(this, "FavoriteMapImage");
  134. //Setup the recent achievement list by adding all achieved achievements to the list
  135. m_pRecentAchievementsList = new vgui::PanelListPanel(this, "RecentAchievementsListPanel");
  136. m_pRecentAchievementsList->SetFirstColumnWidth(0);
  137. ListenForGameEvent( "player_stats_updated" );
  138. ListenForGameEvent( "achievement_earned_local" );
  139. m_bRecentAchievementsDirty = true;
  140. m_bStatsDirty = true;
  141. }
  142. CStatsSummary::~CStatsSummary()
  143. {
  144. if (m_pRecentAchievementsList)
  145. {
  146. m_pRecentAchievementsList->DeleteAllItems();
  147. }
  148. delete m_pRecentAchievementsList;
  149. delete m_pImageList;
  150. }
  151. void CStatsSummary::ApplySchemeSettings(vgui::IScheme *pScheme)
  152. {
  153. BaseClass::ApplySchemeSettings(pScheme);
  154. LoadControlSettings("Resource/UI/CSStatsSummary.res");
  155. SetBgColor(Color(86,86,86,255));
  156. if (m_pImageList)
  157. delete m_pImageList;
  158. m_pImageList = new ImageList(false);
  159. if (m_pImageList)
  160. {
  161. //Load defaults
  162. m_iDefaultWeaponImage = m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/defaultweapon", true));
  163. m_iDefaultMapImage = m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_cs_generic_map", true));
  164. //load weapon images
  165. m_StatImageMap.Insert(CSSTAT_KILLS_DEAGLE, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/deserteagle", true)));
  166. m_StatImageMap.Insert(CSSTAT_KILLS_USP, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/usp45", true)));
  167. m_StatImageMap.Insert(CSSTAT_KILLS_GLOCK, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/glock18", true)));
  168. m_StatImageMap.Insert(CSSTAT_KILLS_P228, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/p228", true)));
  169. m_StatImageMap.Insert(CSSTAT_KILLS_ELITE, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/elites", true)));
  170. m_StatImageMap.Insert(CSSTAT_KILLS_FIVESEVEN, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/fiveseven", true)));
  171. m_StatImageMap.Insert(CSSTAT_KILLS_AWP, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/awp", true)));
  172. m_StatImageMap.Insert(CSSTAT_KILLS_AK47, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/ak47", true)));
  173. m_StatImageMap.Insert(CSSTAT_KILLS_M4A1, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/m4a1", true)));
  174. m_StatImageMap.Insert(CSSTAT_KILLS_AUG, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/aug", true)));
  175. m_StatImageMap.Insert(CSSTAT_KILLS_SG552, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/sg552", true)));
  176. m_StatImageMap.Insert(CSSTAT_KILLS_SG550, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/sg550", true)));
  177. m_StatImageMap.Insert(CSSTAT_KILLS_GALIL, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/galil", true)));
  178. m_StatImageMap.Insert(CSSTAT_KILLS_FAMAS, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/famas", true)));
  179. m_StatImageMap.Insert(CSSTAT_KILLS_SCOUT, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/scout", true)));
  180. m_StatImageMap.Insert(CSSTAT_KILLS_G3SG1, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/g3sg1", true)));
  181. m_StatImageMap.Insert(CSSTAT_KILLS_P90, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/p90", true)));
  182. m_StatImageMap.Insert(CSSTAT_KILLS_MP5NAVY, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/mp5", true)));
  183. m_StatImageMap.Insert(CSSTAT_KILLS_TMP, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/tmp", true)));
  184. m_StatImageMap.Insert(CSSTAT_KILLS_MAC10, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/mac10", true)));
  185. m_StatImageMap.Insert(CSSTAT_KILLS_UMP45, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/ump45", true)));
  186. m_StatImageMap.Insert(CSSTAT_KILLS_M3, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/m3", true)));
  187. m_StatImageMap.Insert(CSSTAT_KILLS_XM1014, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/xm1014", true)));
  188. m_StatImageMap.Insert(CSSTAT_KILLS_M249, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/fav_weap/m249", true)));
  189. //load map images
  190. m_StatImageMap.Insert(CSSTAT_MAP_WINS_CS_ASSAULT, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_cs_assault", true)));
  191. m_StatImageMap.Insert(CSSTAT_MAP_WINS_CS_COMPOUND, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_cs_compound", true)));
  192. m_StatImageMap.Insert(CSSTAT_MAP_WINS_CS_HAVANA, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_cs_havana", true)));
  193. m_StatImageMap.Insert(CSSTAT_MAP_WINS_CS_ITALY, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_cs_italy", true)));
  194. m_StatImageMap.Insert(CSSTAT_MAP_WINS_CS_MILITIA, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_cs_militia", true)));
  195. m_StatImageMap.Insert(CSSTAT_MAP_WINS_CS_OFFICE, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_cs_office", true)));
  196. m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_AZTEC, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_aztec", true)));
  197. m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_CBBLE, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_cbble", true)));
  198. m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_CHATEAU, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_chateau", true)));
  199. m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_DUST2, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_dust2", true)));
  200. m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_DUST, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_dust", true)));
  201. m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_INFERNO, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_inferno", true)));
  202. m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_NUKE, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_nuke", true)));
  203. m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_PIRANESI, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_piranesi", true)));
  204. m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_PORT, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_port", true)));
  205. m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_PRODIGY, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_prodigy", true)));
  206. m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_TIDES, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_tides", true)));
  207. m_StatImageMap.Insert(CSSTAT_MAP_WINS_DE_TRAIN, m_pImageList->AddImage(scheme()->GetImage("gfx/vgui/summary_maps/summary_de_train", true)));
  208. }
  209. }
  210. //----------------------------------------------------------
  211. // Get the width we're going to lock at
  212. //----------------------------------------------------------
  213. void CStatsSummary::ApplySettings(KeyValues *pResourceData)
  214. {
  215. m_iFixedWidth = pResourceData->GetInt("wide", 512);
  216. BaseClass::ApplySettings(pResourceData);
  217. }
  218. //----------------------------------------------------------
  219. // Preserve our width to the one in the .res file
  220. //----------------------------------------------------------
  221. void CStatsSummary::OnSizeChanged(int newWide, int newTall)
  222. {
  223. // Lock the width, but allow height scaling
  224. if (newWide != m_iFixedWidth)
  225. {
  226. SetSize(m_iFixedWidth, newTall);
  227. return;
  228. }
  229. BaseClass::OnSizeChanged(newWide, newTall);
  230. }
  231. void CStatsSummary::OnThink()
  232. {
  233. if ( m_bRecentAchievementsDirty )
  234. UpdateRecentAchievements();
  235. if ( m_bStatsDirty )
  236. UpdateStatsData();
  237. }
  238. void CStatsSummary::OnPageShow()
  239. {
  240. UpdateStatsData();
  241. UpdateRecentAchievements();
  242. }
  243. //----------------------------------------------------------
  244. // Update all of the stats displays
  245. //----------------------------------------------------------
  246. void CStatsSummary::UpdateStatsData()
  247. {
  248. UpdateStatsSummary();
  249. UpdateKillHistory();
  250. UpdateFavoriteWeaponData();
  251. UpdateMapsData();
  252. UpdateLastMatchStats();
  253. m_pStatCard->UpdateInfo();
  254. m_bStatsDirty = false;
  255. }
  256. //----------------------------------------------------------
  257. // Update the stats located in the stats summary section
  258. //----------------------------------------------------------
  259. void CStatsSummary::UpdateStatsSummary()
  260. {
  261. DisplayCompressedLocalizedStat(CSSTAT_ROUNDS_PLAYED, "roundsplayed");
  262. DisplayCompressedLocalizedStat(CSSTAT_ROUNDS_WON, "roundswon");
  263. DisplayCompressedLocalizedStat(CSSTAT_SHOTS_HIT, "shotshit");
  264. DisplayCompressedLocalizedStat(CSSTAT_SHOTS_FIRED, "shotsfired");
  265. wchar_t tempWNumString[STAT_NUM_ARRAY_LENGTH];
  266. //Calculate Win Ratio
  267. int wins = g_CSClientGameStats.GetStatById(CSSTAT_ROUNDS_WON).iStatValue;
  268. int rounds = g_CSClientGameStats.GetStatById(CSSTAT_ROUNDS_PLAYED).iStatValue;
  269. float winRatio = 0;
  270. if (rounds > 0)
  271. {
  272. winRatio = ((float)wins / (float)rounds) * 100.0f;
  273. }
  274. V_snwprintf(tempWNumString, ARRAYSIZE(tempWNumString), L"%.1f%%", winRatio);
  275. SetDialogVariable("winratio", tempWNumString);
  276. //Calculate accuracy
  277. int hits = g_CSClientGameStats.GetStatById(CSSTAT_SHOTS_HIT).iStatValue;
  278. int shots = g_CSClientGameStats.GetStatById(CSSTAT_SHOTS_FIRED).iStatValue;
  279. float accuracy = 0;
  280. if (shots > 0)
  281. {
  282. accuracy = ((float)hits / (float)shots) * 100.0f;
  283. }
  284. V_snwprintf(tempWNumString, ARRAYSIZE(tempWNumString), L"%.1f%%", accuracy);
  285. SetDialogVariable("hitratio", tempWNumString);
  286. }
  287. //----------------------------------------------------------
  288. // Update the stats located in the stats summary section
  289. //----------------------------------------------------------
  290. void CStatsSummary::UpdateKillHistory()
  291. {
  292. DisplayCompressedLocalizedStat(CSSTAT_KILLS, "kills");
  293. DisplayCompressedLocalizedStat(CSSTAT_DEATHS, "deaths");
  294. wchar_t tempWNumString[STAT_NUM_ARRAY_LENGTH];
  295. //Calculate Win Ratio
  296. int kills = g_CSClientGameStats.GetStatById(CSSTAT_KILLS).iStatValue;
  297. int deaths = g_CSClientGameStats.GetStatById(CSSTAT_DEATHS).iStatValue;
  298. float killDeathRatio = 0;
  299. if (deaths > 0)
  300. {
  301. killDeathRatio = (float)kills / (float)deaths;
  302. }
  303. V_snwprintf(tempWNumString, ARRAYSIZE(tempWNumString), L"%.1f", killDeathRatio);
  304. SetDialogVariable("killdeathratio", tempWNumString);
  305. }
  306. //----------------------------------------------------------
  307. // Update the stats located in the favorite weapon section
  308. //----------------------------------------------------------
  309. void CStatsSummary::UpdateFavoriteWeaponData()
  310. {
  311. // First set the image to the favorite weapon
  312. if (m_pImageList)
  313. {
  314. //start with a dummy stat
  315. const WeaponName_StatId* pFavoriteWeaponStatEntry = NULL;
  316. //Find the weapon stat with the most kills
  317. int numKills = 0;
  318. for (int i = 0; WeaponName_StatId_Table[i].killStatId != CSSTAT_UNDEFINED; ++i)
  319. {
  320. // ignore weapons with no hit counts (knife and grenade)
  321. if (WeaponName_StatId_Table[i].hitStatId == CSSTAT_UNDEFINED )
  322. continue;
  323. const WeaponName_StatId& weaponStatEntry = WeaponName_StatId_Table[i];
  324. PlayerStatData_t stat = g_CSClientGameStats.GetStatById(weaponStatEntry.killStatId);
  325. if (stat.iStatValue > numKills)
  326. {
  327. pFavoriteWeaponStatEntry = &weaponStatEntry;
  328. numKills = stat.iStatValue;
  329. }
  330. }
  331. if (pFavoriteWeaponStatEntry)
  332. {
  333. CUtlMap<CSStatType_t, int>::IndexType_t idx = m_StatImageMap.Find((CSStatType_t)pFavoriteWeaponStatEntry->killStatId);
  334. if (m_StatImageMap.IsValidIndex(idx))
  335. {
  336. m_pImagePanelFavWeapon->SetImage(m_pImageList->GetImage(m_StatImageMap[idx]));
  337. }
  338. DisplayCompressedLocalizedStat(pFavoriteWeaponStatEntry->hitStatId, "weaponhits", "#GameUI_Stats_WeaponShotsHit");
  339. DisplayCompressedLocalizedStat(pFavoriteWeaponStatEntry->shotStatId, "weaponshotsfired", "#GameUI_Stats_WeaponShotsFired");
  340. DisplayCompressedLocalizedStat(pFavoriteWeaponStatEntry->killStatId, "weaponkills", "#GameUI_Stats_WeaponKills");
  341. //Calculate accuracy
  342. int kills = g_CSClientGameStats.GetStatById(pFavoriteWeaponStatEntry->killStatId).iStatValue;
  343. int shots = g_CSClientGameStats.GetStatById(pFavoriteWeaponStatEntry->shotStatId).iStatValue;
  344. float killsPerShot = 0;
  345. if (shots > 0)
  346. {
  347. killsPerShot = (float)kills / (float)shots;
  348. }
  349. wchar_t tempWNumString[STAT_NUM_ARRAY_LENGTH];
  350. V_snwprintf(tempWNumString, ARRAYSIZE(tempWNumString), L"%.1f", (killsPerShot));
  351. DisplayFormattedLabel("#GameUI_Stats_WeaponKillRatio", tempWNumString, "weaponkillratio");
  352. }
  353. else
  354. {
  355. if (m_iDefaultWeaponImage != -1)
  356. {
  357. m_pImagePanelFavWeapon->SetImage(m_pImageList->GetImage(m_iDefaultWeaponImage));
  358. }
  359. DisplayFormattedLabel("#GameUI_Stats_WeaponShotsHit", L"0", "weaponhits");
  360. DisplayFormattedLabel("#GameUI_Stats_WeaponShotsFired", L"0", "weaponshotsfired");
  361. DisplayFormattedLabel("#GameUI_Stats_WeaponKills", L"0", "weaponkills");
  362. DisplayFormattedLabel("#GameUI_Stats_WeaponKillRatio", L"0", "weaponkillratio");
  363. }
  364. }
  365. }
  366. //----------------------------------------------------------
  367. // Update the stats located in the favorite weapon section
  368. //----------------------------------------------------------
  369. void CStatsSummary::UpdateMapsData()
  370. {
  371. //start with a dummy stat
  372. const MapName_MapStatId* pFavoriteMapStat = NULL;
  373. int numRounds = 0;
  374. for (int i = 0; MapName_StatId_Table[i].statWinsId != CSSTAT_UNDEFINED; ++i)
  375. {
  376. const MapName_MapStatId& mapStatId = MapName_StatId_Table[i];
  377. PlayerStatData_t stat = g_CSClientGameStats.GetStatById(mapStatId.statRoundsId);
  378. if (stat.iStatValue > numRounds)
  379. {
  380. pFavoriteMapStat = &mapStatId;
  381. numRounds = stat.iStatValue;
  382. }
  383. }
  384. if (pFavoriteMapStat)
  385. {
  386. CUtlMap<CSStatType_t, int>::IndexType_t idx = m_StatImageMap.Find((CSStatType_t)pFavoriteMapStat->statWinsId);
  387. if (m_StatImageMap.IsValidIndex(idx))
  388. {
  389. m_pImagePanelFavMap->SetImage(m_pImageList->GetImage(m_StatImageMap[idx]));
  390. }
  391. // map name
  392. SetDialogVariable("mapname", pFavoriteMapStat->szMapName);
  393. // rounds played
  394. DisplayCompressedLocalizedStat(pFavoriteMapStat->statRoundsId,"mapplayed", "#GameUI_Stats_MapPlayed");
  395. DisplayCompressedLocalizedStat(pFavoriteMapStat->statWinsId, "mapwins", "#GameUI_Stats_MapWins");
  396. //Calculate Win Ratio
  397. int wins = g_CSClientGameStats.GetStatById(pFavoriteMapStat->statWinsId).iStatValue;
  398. int rounds = g_CSClientGameStats.GetStatById(pFavoriteMapStat->statRoundsId).iStatValue;
  399. float winRatio = 0;
  400. if (rounds > 0)
  401. {
  402. winRatio = ((float)wins / (float)rounds) * 100.0f;
  403. }
  404. wchar_t tempWNumString[STAT_NUM_ARRAY_LENGTH];
  405. V_snwprintf(tempWNumString, ARRAYSIZE(tempWNumString), L"%.1f%%", winRatio);
  406. DisplayFormattedLabel("#GameUI_Stats_MapWinRatio", tempWNumString, "mapwinratio");
  407. }
  408. else
  409. {
  410. if (m_iDefaultMapImage != -1)
  411. {
  412. m_pImagePanelFavMap->SetImage(m_pImageList->GetImage(m_iDefaultMapImage));
  413. }
  414. SetDialogVariable("mapname", L"");
  415. DisplayFormattedLabel("#GameUI_Stats_MapPlayed", L"0", "mapplayed");
  416. DisplayFormattedLabel("#GameUI_Stats_MapWins", L"0", "mapwins");
  417. DisplayFormattedLabel("#GameUI_Stats_MapWinRatio", L"0", "mapwinratio");
  418. }
  419. }
  420. int CStatsSummary::AchivementDateSortPredicate( CCSBaseAchievement* const* pLeft, CCSBaseAchievement* const* pRight )
  421. {
  422. if (!pLeft || !pRight || !(*pLeft) || ! (*pRight))
  423. {
  424. return 0;
  425. }
  426. if ((*pLeft)->GetSortKey() < (*pRight)->GetSortKey())
  427. {
  428. return 1;
  429. }
  430. else if ((*pLeft)->GetSortKey() > (*pRight)->GetSortKey())
  431. {
  432. return -1;
  433. }
  434. else
  435. {
  436. return 0;
  437. }
  438. }
  439. void CStatsSummary::UpdateRecentAchievements()
  440. {
  441. CUtlVector<CCSBaseAchievement*> sortedAchivementList;
  442. //Get a list of all the achievements that have been earned
  443. int iCount = g_AchievementMgrCS.GetAchievementCount();
  444. sortedAchivementList.EnsureCapacity(iCount);
  445. for (int i = 0; i < iCount; ++i)
  446. {
  447. CCSBaseAchievement* pAchievement = (CCSBaseAchievement*)g_AchievementMgrCS.GetAchievementByIndex(i);
  448. if (pAchievement && pAchievement->IsAchieved())
  449. {
  450. sortedAchivementList.AddToTail(pAchievement);
  451. }
  452. }
  453. //Sort the earned achievements by time and date earned.
  454. sortedAchivementList.Sort(AchivementDateSortPredicate);
  455. //Clear the UI list
  456. m_pRecentAchievementsList->DeleteAllItems();
  457. // Add each achievement in the sorted list as a panel.
  458. int numPanelsToAdd = MIN(maxRecentAchievementToDisplay, sortedAchivementList.Count());
  459. for ( int i = 0; i < numPanelsToAdd; i++ )
  460. {
  461. CCSBaseAchievement* pAchievement = sortedAchivementList[i];
  462. if (pAchievement)
  463. {
  464. CAchievementsPageItemPanel *achievementItemPanel = new CAchievementsPageItemPanel(m_pRecentAchievementsList, "AchievementDialogItemPanel");
  465. achievementItemPanel->SetAchievementInfo(pAchievement);
  466. // force all our new panel to have the correct internal layout and size so that our parent container can layout properly
  467. achievementItemPanel->InvalidateLayout(true, true);
  468. m_pRecentAchievementsList->AddItem(NULL, achievementItemPanel);
  469. }
  470. }
  471. m_bRecentAchievementsDirty = false;
  472. }
  473. void CStatsSummary::UpdateLastMatchStats()
  474. {
  475. DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_T_ROUNDS_WON, "lastmatchtwins", "#GameUI_Stats_LastMatch_TWins");
  476. DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_CT_ROUNDS_WON, "lastmatchctwins", "#GameUI_Stats_LastMatch_CTWins");
  477. DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_ROUNDS_WON, "lastmatchwins", "#GameUI_Stats_LastMatch_RoundsWon");
  478. DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_MAX_PLAYERS, "lastmatchmaxplayers", "#GameUI_Stats_LastMatch_MaxPlayers");
  479. DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_MVPS, "lastmatchstars", "#GameUI_Stats_LastMatch_MVPS");
  480. DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_KILLS, "lastmatchkills", "#GameUI_Stats_WeaponKills");
  481. DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_DEATHS, "lastmatchdeaths", "#GameUI_Stats_LastMatch_Deaths");
  482. DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_DAMAGE, "lastmatchtotaldamage", "#GameUI_Stats_LastMatch_Damage");
  483. DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_DOMINATIONS, "lastmatchdominations", "#GameUI_Stats_LastMatch_Dominations");
  484. DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_REVENGES, "lastmatchrevenges", "#GameUI_Stats_LastMatch_Revenges");
  485. UpdateLastMatchFavoriteWeaponStats();
  486. wchar_t tempWNumString[STAT_NUM_ARRAY_LENGTH];
  487. //Calculate Kill:Death ratio
  488. int deaths = g_CSClientGameStats.GetStatById(CSSTAT_LASTMATCH_DEATHS).iStatValue;
  489. int kills = g_CSClientGameStats.GetStatById(CSSTAT_LASTMATCH_KILLS).iStatValue;
  490. float killDeathRatio = deaths;
  491. if (deaths != 0)
  492. {
  493. killDeathRatio = (float)kills / (float)deaths;
  494. }
  495. V_snwprintf(tempWNumString, ARRAYSIZE(tempWNumString), L"%.1f", killDeathRatio);
  496. DisplayFormattedLabel("#GameUI_Stats_LastMatch_KDRatio", tempWNumString, "lastmatchkilldeathratio");
  497. //Calculate cost per kill
  498. PlayerStatData_t statMoneySpent = g_CSClientGameStats.GetStatById(CSSTAT_LASTMATCH_MONEYSPENT);
  499. int costPerKill = 0;
  500. if (kills > 0)
  501. {
  502. costPerKill = statMoneySpent.iStatValue / kills;
  503. }
  504. ConvertNumberToMantissaSuffixForm(costPerKill, tempWNumString, STAT_NUM_ARRAY_LENGTH);
  505. DisplayFormattedLabel("#GameUI_Stats_LastMatch_MoneySpentPerKill", tempWNumString, "lastmatchmoneyspentperkill");
  506. }
  507. void CStatsSummary::UpdateLastMatchFavoriteWeaponStats()
  508. {
  509. wchar_t tempWNumString[STAT_NUM_ARRAY_LENGTH];
  510. PlayerStatData_t statFavWeaponId = g_CSClientGameStats.GetStatById(CSSTAT_LASTMATCH_FAVWEAPON_ID);
  511. const WeaponName_StatId& favoriteWeaponStat = GetWeaponTableEntryFromWeaponId((CSWeaponID)statFavWeaponId.iStatValue);
  512. // If we have a valid weapon use it's data; otherwise use nothing. We check the shot ID to make sure it is a weapon with bullets.
  513. if (favoriteWeaponStat.hitStatId != CSSTAT_UNDEFINED)
  514. {
  515. // Set the image and (non-copyright) name of this weapon
  516. CUtlMap<CSStatType_t, int>::IndexType_t idx = m_StatImageMap.Find((CSStatType_t)favoriteWeaponStat.killStatId);
  517. if (m_StatImageMap.IsValidIndex(idx))
  518. {
  519. m_pImagePanelLastMapFavWeapon->SetImage(m_pImageList->GetImage(m_StatImageMap[idx]));
  520. }
  521. const wchar_t* tempName = WeaponIDToDisplayName(favoriteWeaponStat.weaponId);
  522. if (tempName)
  523. {
  524. SetDialogVariable("lastmatchfavweaponname", tempName);
  525. }
  526. else
  527. {
  528. SetDialogVariable("lastmatchfavweaponname", L"");
  529. }
  530. DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_FAVWEAPON_KILLS, "lastmatchfavweaponkills", "#GameUI_Stats_WeaponKills");
  531. DisplayCompressedLocalizedStat(CSSTAT_LASTMATCH_FAVWEAPON_HITS, "lastmatchfavweaponhits", "#GameUI_Stats_WeaponShotsHit");
  532. int shots = g_CSClientGameStats.GetStatById(CSSTAT_LASTMATCH_FAVWEAPON_SHOTS).iStatValue;
  533. int hits = g_CSClientGameStats.GetStatById(CSSTAT_LASTMATCH_FAVWEAPON_HITS).iStatValue;
  534. float accuracy = 0.0f;
  535. if (shots != 0)
  536. {
  537. accuracy = ((float)hits / (float)shots) * 100.0f;
  538. }
  539. V_snwprintf(tempWNumString, ARRAYSIZE(tempWNumString), L"%.1f%%", accuracy);
  540. DisplayFormattedLabel("#GameUI_Stats_LastMatch_FavWeaponAccuracy", tempWNumString, "lastmatchfavweaponaccuracy");
  541. }
  542. else
  543. {
  544. if (m_iDefaultWeaponImage != -1)
  545. {
  546. m_pImagePanelLastMapFavWeapon->SetImage(m_pImageList->GetImage(m_iDefaultWeaponImage));
  547. }
  548. //Set this label to diferent text, indicating that there is not a favorite weapon
  549. SetDialogVariable("lastmatchfavweaponname", g_pVGuiLocalize->Find("#GameUI_Stats_LastMatch_NoFavWeapon"));
  550. DisplayFormattedLabel("#GameUI_Stats_WeaponKills", L"0", "lastmatchfavweaponkills");
  551. DisplayFormattedLabel("#GameUI_Stats_WeaponShotsHit", L"0", "lastmatchfavweaponhits");
  552. DisplayFormattedLabel("#GameUI_Stats_LastMatch_FavWeaponAccuracy", L"0", "lastmatchfavweaponaccuracy");
  553. }
  554. }
  555. void CStatsSummary::FireGameEvent( IGameEvent *event )
  556. {
  557. const char *type = event->GetName();
  558. if ( 0 == Q_strcmp( type, "achievement_earned_local" ) )
  559. {
  560. m_bRecentAchievementsDirty = true;
  561. }
  562. else if ( 0 == Q_strcmp( type, "player_stats_updated" ) )
  563. {
  564. m_bStatsDirty = true;
  565. }
  566. }
  567. void CStatsSummary::DisplayCompressedLocalizedStat(CSStatType_t stat, const char* dialogVariable, const char* localizationToken /* = NULL */)
  568. {
  569. wchar_t tempWNumString[STAT_NUM_ARRAY_LENGTH];
  570. int statValue = g_CSClientGameStats.GetStatById(stat).iStatValue;
  571. ConvertNumberToMantissaSuffixForm(statValue, tempWNumString, STAT_NUM_ARRAY_LENGTH);
  572. if (localizationToken)
  573. {
  574. DisplayFormattedLabel(localizationToken, tempWNumString, dialogVariable);
  575. }
  576. else
  577. {
  578. SetDialogVariable(dialogVariable, tempWNumString);
  579. }
  580. }
  581. void CStatsSummary::DisplayFormattedLabel( const char* localizationToken, const wchar_t* valueText, const char* dialogVariable )
  582. {
  583. wchar_t tempWStatString[256];
  584. g_pVGuiLocalize->ConstructString(tempWStatString, sizeof(tempWStatString),
  585. g_pVGuiLocalize->Find(localizationToken), 1, valueText);
  586. SetDialogVariable(dialogVariable, tempWStatString);
  587. }