Achievements.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "Game_local.h"
  23. #include "..\..\doomclassic\doom\doomdef.h"
  24. idCVar achievements_Verbose( "achievements_Verbose", "1", CVAR_BOOL, "debug spam" );
  25. idCVar g_demoMode( "g_demoMode", "0", CVAR_INTEGER, "this is a demo" );
  26. bool idAchievementManager::cheatingDialogShown = false;
  27. const struct achievementInfo_t {
  28. int required;
  29. bool lifetime; // true means the current count is stored on the player profile. Doesn't matter for single count achievements.
  30. } achievementInfo [ACHIEVEMENTS_NUM] = {
  31. { 50, true }, // ACHIEVEMENT_EARN_ALL_50_TROPHIES
  32. { 1, true }, // ACHIEVEMENT_COMPLETED_DIFFICULTY_0
  33. { 1, true }, // ACHIEVEMENT_COMPLETED_DIFFICULTY_1
  34. { 1, true }, // ACHIEVEMENT_COMPLETED_DIFFICULTY_2
  35. { 1, true }, // ACHIEVEMENT_COMPLETED_DIFFICULTY_3
  36. { 64, false }, // ACHIEVEMENT_PDAS_BASE
  37. { 14, false }, // ACHIEVEMENT_WATCH_ALL_VIDEOS
  38. { 1, false }, // ACHIEVEMENT_KILL_MONSTER_WITH_1_HEALTH_LEFT
  39. { 35, false }, // ACHIEVEMENT_OPEN_ALL_LOCKERS
  40. { 20, true }, // ACHIEVEMENT_KILL_20_ENEMY_FISTS_HANDS
  41. { 1, true }, // ACHIEVEMENT_KILL_SCI_NEXT_TO_RCR
  42. { 1, true }, // ACHIEVEMENT_KILL_TWO_IMPS_ONE_SHOTGUN
  43. { 1, true }, // ACHIEVEMENT_SCORE_25000_TURKEY_PUNCHER
  44. { 50, true }, // ACHIEVEMENT_DESTROY_BARRELS
  45. { 1, true }, // ACHIEVEMENT_GET_BFG_FROM_SECURITY_OFFICE
  46. { 1, true }, // ACHIEVEMENT_COMPLETE_LEVEL_WITHOUT_TAKING_DMG
  47. { 1, true }, // ACHIEVEMENT_FIND_RAGE_LOGO
  48. { 1, true }, // ACHIEVEMENT_SPEED_RUN
  49. { 1, true }, // ACHIEVEMENT_DEFEAT_VAGARY_BOSS
  50. { 1, true }, // ACHIEVEMENT_DEFEAT_GUARDIAN_BOSS
  51. { 1, true }, // ACHIEVEMENT_DEFEAT_SABAOTH_BOSS
  52. { 1, true }, // ACHIEVEMENT_DEFEAT_CYBERDEMON_BOSS
  53. { 1, true }, // ACHIEVEMENT_SENTRY_BOT_ALIVE_TO_DEST
  54. { 20, true }, // ACHIEVEMENT_KILL_20_ENEMY_WITH_CHAINSAW
  55. { 1, true }, // ACHIEVEMENT_ID_LOGO_SECRET_ROOM
  56. { 1, true }, // ACHIEVEMENT_BLOODY_HANDWORK_OF_BETRUGER
  57. { 1, true }, // ACHIEVEMENT_TWO_DEMONS_FIGHT_EACH_OTHER
  58. { 20, true }, // ACHIEVEMENT_USE_SOUL_CUBE_TO_DEFEAT_20_ENEMY
  59. { 1, true }, // ACHIEVEMENT_ROE_COMPLETED_DIFFICULTY_0
  60. { 1, true }, // ACHIEVEMENT_ROE_COMPLETED_DIFFICULTY_1
  61. { 1, true }, // ACHIEVEMENT_ROE_COMPLETED_DIFFICULTY_2
  62. { 1, true }, // ACHIEVEMENT_ROE_COMPLETED_DIFFICULTY_3
  63. { 22, false }, // ACHIEVEMENT_PDAS_ROE
  64. { 1, true }, // ACHIEVEMENT_KILL_5_ENEMY_HELL_TIME
  65. { 1, true }, // ACHIEVEMENT_DEFEAT_HELLTIME_HUNTER
  66. { 1, true }, // ACHIEVEMENT_DEFEAT_BERSERK_HUNTER
  67. { 1, true }, // ACHIEVEMENT_DEFEAT_INVULNERABILITY_HUNTER
  68. { 1, true }, // ACHIEVEMENT_DEFEAT_MALEDICT_BOSS
  69. { 20, true }, // ACHIEVEMENT_GRABBER_KILL_20_ENEMY
  70. { 20, true }, // ACHIEVEMENT_ARTIFACT_WITH_BERSERK_PUNCH_20
  71. { 1, true }, // ACHIEVEMENT_LE_COMPLETED_DIFFICULTY_0
  72. { 1, true }, // ACHIEVEMENT_LE_COMPLETED_DIFFICULTY_1
  73. { 1, true }, // ACHIEVEMENT_LE_COMPLETED_DIFFICULTY_2
  74. { 1, true }, // ACHIEVEMENT_LE_COMPLETED_DIFFICULTY_3
  75. { 10, false }, // ACHIEVEMENT_PDAS_LE
  76. { 1, true }, // ACHIEVEMENT_MP_KILL_PLAYER_VIA_TELEPORT
  77. { 1, true }, // ACHIEVEMENT_MP_CATCH_ENEMY_IN_ROFC
  78. { 5, true }, // ACHIEVEMENT_MP_KILL_5_PLAYERS_USING_INVIS
  79. { 1, true }, // ACHIEVEMENT_MP_COMPLETE_MATCH_WITHOUT_DYING
  80. { 1, true }, // ACHIEVEMENT_MP_USE_BERSERK_TO_KILL_PLAYER
  81. { 1, true }, // ACHIEVEMENT_MP_KILL_2_GUYS_IN_ROOM_WITH_BFG
  82. };
  83. /*
  84. ================================================================================================
  85. idAchievementManager
  86. ================================================================================================
  87. */
  88. /*
  89. ========================
  90. idAchievementManager::idAchievementManager
  91. ========================
  92. */
  93. idAchievementManager::idAchievementManager() :
  94. lastImpKilledTime( 0 ),
  95. lastPlayerKilledTime( 0 ),
  96. playerTookDamage( false ) {
  97. counts.Zero();
  98. ResetHellTimeKills();
  99. }
  100. /*
  101. ========================
  102. idAchievementManager::Init
  103. ========================
  104. */
  105. void idAchievementManager::Init( idPlayer * player ) {
  106. owner = player;
  107. SyncAchievments();
  108. }
  109. /*
  110. ========================
  111. idAchievementManager::SyncAchievments
  112. ========================
  113. */
  114. void idAchievementManager::SyncAchievments() {
  115. idLocalUser * user = GetLocalUser();
  116. if ( user == NULL || user->GetProfile() == NULL ) {
  117. return;
  118. }
  119. // Set achievement counts
  120. for ( int i = 0; i < counts.Num(); i++ ) {
  121. if ( user->GetProfile()->GetAchievement( i ) ) {
  122. counts[i] = achievementInfo[i].required;
  123. } else if ( achievementInfo[i].lifetime ) {
  124. counts[i] = user->GetStatInt( i );
  125. }
  126. }
  127. }
  128. /*
  129. ========================
  130. idAchievementManager::GetLocalUser
  131. ========================
  132. */
  133. idLocalUser * idAchievementManager::GetLocalUser() {
  134. if ( !verify( owner != NULL ) ) {
  135. return NULL;
  136. }
  137. return session->GetGameLobbyBase().GetLocalUserFromLobbyUser( gameLocal.lobbyUserIDs[ owner->GetEntityNumber() ] );
  138. }
  139. /*
  140. ========================
  141. idAchievementManager::Save
  142. ========================
  143. */
  144. void idAchievementManager::Save( idSaveGame * savefile ) const {
  145. owner.Save( savefile );
  146. for ( int i = 0; i < ACHIEVEMENTS_NUM; i++ ) {
  147. savefile->WriteInt( counts[i] );
  148. }
  149. savefile->WriteInt( lastImpKilledTime );
  150. savefile->WriteInt( lastPlayerKilledTime );
  151. savefile->WriteBool( playerTookDamage );
  152. savefile->WriteInt( currentHellTimeKills );
  153. }
  154. /*
  155. ========================
  156. idAchievementManager::Restore
  157. ========================
  158. */
  159. void idAchievementManager::Restore( idRestoreGame * savefile ) {
  160. owner.Restore( savefile );
  161. for ( int i = 0; i < ACHIEVEMENTS_NUM; i++ ) {
  162. savefile->ReadInt( counts[i] );
  163. }
  164. savefile->ReadInt( lastImpKilledTime );
  165. savefile->ReadInt( lastPlayerKilledTime );
  166. savefile->ReadBool( playerTookDamage );
  167. savefile->ReadInt( currentHellTimeKills );
  168. SyncAchievments();
  169. }
  170. /*
  171. ========================
  172. idAchievementManager::EventCompletesAchievement
  173. ========================
  174. */
  175. void idAchievementManager::EventCompletesAchievement( const achievement_t eventId ) {
  176. if ( g_demoMode.GetBool() ) {
  177. return;
  178. }
  179. idLocalUser * localUser = GetLocalUser();
  180. if ( localUser == NULL || localUser->GetProfile() == NULL ) {
  181. // Send a Reliable Message to the User that needs to unlock this.
  182. if ( owner != NULL ) {
  183. int playerId = owner->entityNumber;
  184. const int bufferSize = sizeof( playerId ) + sizeof( eventId );
  185. byte buffer[ bufferSize ];
  186. idBitMsg msg;
  187. msg.InitWrite( buffer, bufferSize );
  188. msg.WriteByte( playerId );
  189. msg.WriteByte( eventId );
  190. msg.WriteByteAlign();
  191. idLib::Printf( "Host Sending Achievement\n");
  192. session->GetActingGameStateLobbyBase().SendReliableToLobbyUser( gameLocal.lobbyUserIDs[ owner->entityNumber ], GAME_RELIABLE_MESSAGE_ACHIEVEMENT_UNLOCK, msg );
  193. }
  194. return; // Remote user or build game
  195. }
  196. // Check to see if we've already given the achievement.
  197. // If so, don't do again because we don't want to autosave every time a trigger is hit
  198. if ( localUser->GetProfile()->GetAchievement( eventId ) ) {
  199. return;
  200. }
  201. #ifdef ID_RETAIL
  202. if ( common->GetConsoleUsed() ) {
  203. if ( !cheatingDialogShown ) {
  204. common->Dialog().AddDialog( GDM_ACHIEVEMENTS_DISABLED_DUE_TO_CHEATING, DIALOG_ACCEPT, NULL, NULL, true );
  205. cheatingDialogShown = true;
  206. }
  207. return;
  208. }
  209. #endif
  210. counts[eventId]++;
  211. if ( counts[eventId] >= achievementInfo[eventId].required ) {
  212. session->GetAchievementSystem().AchievementUnlock( localUser, eventId );
  213. } else {
  214. if ( achievementInfo[eventId].lifetime ) {
  215. localUser->SetStatInt( eventId, counts[eventId] );
  216. }
  217. }
  218. }
  219. /*
  220. ========================
  221. idAchievementManager::IncrementHellTimeKills
  222. ========================
  223. */
  224. void idAchievementManager::IncrementHellTimeKills() {
  225. currentHellTimeKills++;
  226. if ( currentHellTimeKills >= 5 ) {
  227. EventCompletesAchievement( ACHIEVEMENT_KILL_5_ENEMY_HELL_TIME );
  228. }
  229. }
  230. /*
  231. ========================
  232. idAchievementManager::SavePersistentData
  233. ========================
  234. */
  235. void idAchievementManager::SavePersistentData( idDict & playerInfo ) {
  236. for ( int i = 0; i < ACHIEVEMENTS_NUM; ++i ) {
  237. playerInfo.SetInt( va( "ach_%d", i ), counts[i] );
  238. }
  239. }
  240. /*
  241. ========================
  242. idAchievementManager::RestorePersistentData
  243. ========================
  244. */
  245. void idAchievementManager::RestorePersistentData( const idDict & spawnArgs ) {
  246. for( int i = 0; i < ACHIEVEMENTS_NUM; ++i ) {
  247. counts[i] = spawnArgs.GetInt( va( "ach_%d", i), "0" );
  248. }
  249. }
  250. /*
  251. ========================
  252. idAchievementManager::LocalUser_CompleteAchievement
  253. ========================
  254. */
  255. void idAchievementManager::LocalUser_CompleteAchievement( achievement_t id ) {
  256. idLocalUser * localUser = session->GetSignInManager().GetMasterLocalUser();
  257. // Check to see if we've already given the achievement.
  258. // If so, don't do again because we don't want to autosave every time a trigger is hit
  259. if( localUser == NULL || localUser->GetProfile()->GetAchievement( id ) ) {
  260. return;
  261. }
  262. #ifdef ID_RETAIL
  263. if ( common->GetConsoleUsed() ) {
  264. if ( !cheatingDialogShown ) {
  265. common->Dialog().AddDialog( GDM_ACHIEVEMENTS_DISABLED_DUE_TO_CHEATING, DIALOG_ACCEPT, NULL, NULL, true );
  266. cheatingDialogShown = true;
  267. }
  268. return;
  269. }
  270. #endif
  271. session->GetAchievementSystem().AchievementUnlock( localUser, id );
  272. }
  273. /*
  274. ========================
  275. idAchievementManager::CheckDoomClassicsAchievements
  276. Processed when the player finishes a level.
  277. ========================
  278. */
  279. void idAchievementManager::CheckDoomClassicsAchievements( int killcount, int itemcount, int secretcount, int skill, int mission, int map, int episode, int totalkills, int totalitems, int totalsecret ) {
  280. const skill_t difficulty = (skill_t)skill;
  281. const currentGame_t currentGame = common->GetCurrentGame();
  282. const GameMission_t expansion = (GameMission_t)mission;
  283. idLocalUser * localUser = session->GetSignInManager().GetMasterLocalUser();
  284. if ( localUser != NULL && localUser->GetProfile() != NULL ) {
  285. // GENERAL ACHIEVEMENT UNLOCKING.
  286. if( currentGame == DOOM_CLASSIC ) {
  287. LocalUser_CompleteAchievement( ACHIEVEMENT_DOOM1_NEOPHYTE_COMPLETE_ANY_LEVEL );
  288. } else if( currentGame == DOOM2_CLASSIC ) {
  289. LocalUser_CompleteAchievement( ACHIEVEMENT_DOOM2_JUST_GETTING_STARTED_COMPLETE_ANY_LEVEL );
  290. }
  291. // Complete Any Level on Nightmare.
  292. if ( difficulty == sk_nightmare && currentGame == DOOM_CLASSIC ) {
  293. LocalUser_CompleteAchievement( ACHIEVEMENT_DOOM1_NIGHTMARE_COMPLETE_ANY_LEVEL_NIGHTMARE );
  294. }
  295. const bool gotAllKills = killcount >= totalkills;
  296. const bool gotAllItems = itemcount >= totalitems;
  297. const bool gotAllSecrets = secretcount >= totalsecret;
  298. if ( gotAllItems && gotAllKills && gotAllSecrets ) {
  299. if( currentGame == DOOM_CLASSIC ) {
  300. LocalUser_CompleteAchievement( ACHIEVEMENT_DOOM1_BURNING_OUT_OF_CONTROL_COMPLETE_KILLS_ITEMS_SECRETS );
  301. } else if( currentGame == DOOM2_CLASSIC ) {
  302. LocalUser_CompleteAchievement( ACHIEVEMENT_DOOM2_BURNING_OUT_OF_CONTROL_COMPLETE_KILLS_ITEMS_SECRETS );
  303. }
  304. }
  305. // DOOM EXPANSION ACHIEVEMENTS
  306. if( expansion == doom ) {
  307. if( map == 8 ) {
  308. // Medium or higher skill level.
  309. if( difficulty >= sk_medium ) {
  310. localUser->SetStatInt( STAT_DOOM_COMPLETED_EPISODE_1_MEDIUM + ( episode - 1 ), 1 );
  311. }
  312. // Hard or higher skill level.
  313. if( difficulty >= sk_hard ) {
  314. localUser->SetStatInt( STAT_DOOM_COMPLETED_EPISODE_1_HARD + ( episode - 1 ), 1 );
  315. localUser->SetStatInt( STAT_DOOM_COMPLETED_EPISODE_1_MEDIUM + ( episode - 1 ), 1 );
  316. }
  317. if ( difficulty == sk_nightmare ) {
  318. localUser->SetStatInt( STAT_DOOM_COMPLETED_EPISODE_1_HARD + ( episode - 1 ), 1 );
  319. localUser->SetStatInt( STAT_DOOM_COMPLETED_EPISODE_1_MEDIUM + ( episode - 1 ), 1 );
  320. }
  321. // Save the Settings.
  322. localUser->SaveProfileSettings();
  323. }
  324. // Check to see if we've completed all episodes.
  325. const int episode1completed = localUser->GetStatInt( STAT_DOOM_COMPLETED_EPISODE_1_MEDIUM );
  326. const int episode2completed = localUser->GetStatInt( STAT_DOOM_COMPLETED_EPISODE_2_MEDIUM );
  327. const int episode3completed = localUser->GetStatInt( STAT_DOOM_COMPLETED_EPISODE_3_MEDIUM );
  328. const int episode4completed = localUser->GetStatInt( STAT_DOOM_COMPLETED_EPISODE_4_MEDIUM );
  329. const int episode1completed_hard = localUser->GetStatInt( STAT_DOOM_COMPLETED_EPISODE_1_HARD );
  330. const int episode2completed_hard = localUser->GetStatInt( STAT_DOOM_COMPLETED_EPISODE_2_HARD );
  331. const int episode3completed_hard = localUser->GetStatInt( STAT_DOOM_COMPLETED_EPISODE_3_HARD );
  332. const int episode4completed_hard = localUser->GetStatInt( STAT_DOOM_COMPLETED_EPISODE_4_HARD );
  333. if ( currentGame == DOOM_CLASSIC ) {
  334. if ( episode1completed ) {
  335. LocalUser_CompleteAchievement( ACHIEVEMENT_DOOM1_EPISODE1_COMPLETE_MEDIUM );
  336. }
  337. if ( episode2completed ) {
  338. LocalUser_CompleteAchievement( ACHIEVEMENT_DOOM1_EPISODE2_COMPLETE_MEDIUM );
  339. }
  340. if ( episode3completed ) {
  341. LocalUser_CompleteAchievement( ACHIEVEMENT_DOOM1_EPISODE3_COMPLETE_MEDIUM );
  342. }
  343. if ( episode4completed ) {
  344. LocalUser_CompleteAchievement( ACHIEVEMENT_DOOM1_EPISODE4_COMPLETE_MEDIUM );
  345. }
  346. if ( episode1completed_hard && episode2completed_hard && episode3completed_hard && episode4completed_hard ) {
  347. LocalUser_CompleteAchievement( ACHIEVEMENT_DOOM1_RAMPAGE_COMPLETE_ALL_HARD );
  348. }
  349. }
  350. } else if( expansion == doom2 ) {
  351. if( map == 30 ) {
  352. if ( currentGame == DOOM2_CLASSIC ) {
  353. LocalUser_CompleteAchievement( ACHIEVEMENT_DOOM2_FROM_EARTH_TO_HELL_COMPLETE_HELL_ON_EARTH );
  354. if ( difficulty >= sk_hard ) {
  355. LocalUser_CompleteAchievement( ACHIEVEMENT_DOOM2_SUPERIOR_FIREPOWER_COMPLETE_ALL_HARD );
  356. }
  357. }
  358. }
  359. } else if( expansion == pack_nerve ) {
  360. if( map == 8 ) {
  361. if ( currentGame == DOOM2_CLASSIC ) {
  362. LocalUser_CompleteAchievement( ACHIEVEMENT_DOOM2_AND_BACK_AGAIN_COMPLETE_NO_REST );
  363. }
  364. }
  365. }
  366. }
  367. }
  368. /*
  369. =================
  370. AchievementsReset
  371. =================
  372. */
  373. CONSOLE_COMMAND( AchievementsReset, "Lock an achievement", NULL ) {
  374. idLocalUser * user = session->GetSignInManager().GetMasterLocalUser();
  375. if ( user == NULL ) {
  376. idLib::Printf( "Must be signed in\n" );
  377. return;
  378. }
  379. if ( args.Argc() == 1 ) {
  380. for ( int i = 0; i < ACHIEVEMENTS_NUM; i++ ) {
  381. user->SetStatInt( i, 0 );
  382. session->GetAchievementSystem().AchievementLock( user, i );
  383. }
  384. } else {
  385. int i = atoi( args.Argv( 1 ) );
  386. user->SetStatInt( i, 0 );
  387. session->GetAchievementSystem().AchievementLock( user, i );
  388. }
  389. user->SaveProfileSettings();
  390. }
  391. /*
  392. =================
  393. AchievementsUnlock
  394. =================
  395. */
  396. CONSOLE_COMMAND( AchievementsUnlock, "Unlock an achievement", NULL ) {
  397. idLocalUser * user = session->GetSignInManager().GetMasterLocalUser();
  398. if ( user == NULL ) {
  399. idLib::Printf( "Must be signed in\n" );
  400. return;
  401. }
  402. if ( args.Argc() == 1 ) {
  403. for ( int i = 0; i < ACHIEVEMENTS_NUM; i++ ) {
  404. user->SetStatInt( i, achievementInfo[i].required );
  405. session->GetAchievementSystem().AchievementUnlock( user, i );
  406. }
  407. } else {
  408. int i = atoi( args.Argv( 1 ) );
  409. user->SetStatInt( i, achievementInfo[i].required );
  410. session->GetAchievementSystem().AchievementUnlock( user, i );
  411. }
  412. user->SaveProfileSettings();
  413. }
  414. /*
  415. =================
  416. AchievementsList
  417. =================
  418. */
  419. CONSOLE_COMMAND( AchievementsList, "Lists achievements and status", NULL ) {
  420. idPlayer * player = gameLocal.GetLocalPlayer();
  421. idLocalUser * user = ( player == NULL ) ? session->GetSignInManager().GetMasterLocalUser() : session->GetGameLobbyBase().GetLocalUserFromLobbyUser( gameLocal.lobbyUserIDs[ player->GetEntityNumber() ] );
  422. if ( user == NULL ) {
  423. idLib::Printf( "Must be signed in\n" );
  424. return;
  425. }
  426. idPlayerProfile * profile = user->GetProfile();
  427. idArray<bool, 128> achievementState;
  428. bool achievementStateValid = session->GetAchievementSystem().GetAchievementState( user, achievementState );
  429. for ( int i = 0; i < ACHIEVEMENTS_NUM; i++ ) {
  430. const char * pInfo = "";
  431. if ( profile == NULL ) {
  432. pInfo = S_COLOR_RED "unknown" S_COLOR_DEFAULT;
  433. } else if ( !profile->GetAchievement( i ) ) {
  434. pInfo = S_COLOR_YELLOW "locked" S_COLOR_DEFAULT;
  435. } else {
  436. pInfo = S_COLOR_GREEN "unlocked" S_COLOR_DEFAULT;
  437. }
  438. const char * sInfo = "";
  439. if ( !achievementStateValid ) {
  440. sInfo = S_COLOR_RED "unknown" S_COLOR_DEFAULT;
  441. } else if ( !achievementState[i] ) {
  442. sInfo = S_COLOR_YELLOW "locked" S_COLOR_DEFAULT;
  443. } else {
  444. sInfo = S_COLOR_GREEN "unlocked" S_COLOR_DEFAULT;
  445. }
  446. int count = 0;
  447. if ( achievementInfo[i].lifetime ) {
  448. count = user->GetStatInt( i );
  449. } else if ( player != NULL ) {
  450. count = player->GetAchievementManager().GetCount( (achievement_t) i );
  451. } else {
  452. count = 0;
  453. }
  454. achievementDescription_t data;
  455. bool descriptionValid = session->GetAchievementSystem().GetAchievementDescription( user, i, data );
  456. idLib::Printf( "%02d: %2d/%2d | %12.12s | %12.12s | %s%s\n", i, count, achievementInfo[i].required, pInfo, sInfo, descriptionValid ? data.hidden ? "(hidden) " : "" : "(unknown) ", descriptionValid ? data.name : "" );
  457. }
  458. }