ui_sppostgame.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. //
  19. /*
  20. =============================================================================
  21. SINGLE PLAYER POSTGAME MENU
  22. =============================================================================
  23. */
  24. #include "ui_local.h"
  25. #define MAX_SCOREBOARD_CLIENTS 8
  26. #define AWARD_PRESENTATION_TIME 2000
  27. #define ART_MENU0 "menu/art/menu_0"
  28. #define ART_MENU1 "menu/art/menu_1"
  29. #define ART_REPLAY0 "menu/art/replay_0"
  30. #define ART_REPLAY1 "menu/art/replay_1"
  31. #define ART_NEXT0 "menu/art/next_0"
  32. #define ART_NEXT1 "menu/art/next_1"
  33. #define ID_AGAIN 10
  34. #define ID_NEXT 11
  35. #define ID_MENU 12
  36. typedef struct {
  37. menuframework_s menu;
  38. menubitmap_s item_again;
  39. menubitmap_s item_next;
  40. menubitmap_s item_menu;
  41. int phase;
  42. int ignoreKeysTime;
  43. int starttime;
  44. int scoreboardtime;
  45. int serverId;
  46. int clientNums[MAX_SCOREBOARD_CLIENTS];
  47. int ranks[MAX_SCOREBOARD_CLIENTS];
  48. int scores[MAX_SCOREBOARD_CLIENTS];
  49. char placeNames[3][64];
  50. int level;
  51. int numClients;
  52. int won;
  53. int numAwards;
  54. int awardsEarned[6];
  55. int awardsLevels[6];
  56. qboolean playedSound[6];
  57. int lastTier;
  58. sfxHandle_t winnerSound;
  59. } postgameMenuInfo_t;
  60. static postgameMenuInfo_t postgameMenuInfo;
  61. static char arenainfo[MAX_INFO_VALUE];
  62. char *ui_medalNames[] = {"Accuracy", "Impressive", "Excellent", "Gauntlet", "Frags", "Perfect"};
  63. char *ui_medalPicNames[] = {
  64. "menu/medals/medal_accuracy",
  65. "menu/medals/medal_impressive",
  66. "menu/medals/medal_excellent",
  67. "menu/medals/medal_gauntlet",
  68. "menu/medals/medal_frags",
  69. "menu/medals/medal_victory"
  70. };
  71. char *ui_medalSounds[] = {
  72. "sound/feedback/accuracy.wav",
  73. "sound/feedback/impressive_a.wav",
  74. "sound/feedback/excellent_a.wav",
  75. "sound/feedback/gauntlet.wav",
  76. "sound/feedback/frags.wav",
  77. "sound/feedback/perfect.wav"
  78. };
  79. /*
  80. =================
  81. UI_SPPostgameMenu_AgainEvent
  82. =================
  83. */
  84. static void UI_SPPostgameMenu_AgainEvent( void* ptr, int event )
  85. {
  86. if (event != QM_ACTIVATED) {
  87. return;
  88. }
  89. UI_PopMenu();
  90. trap_Cmd_ExecuteText( EXEC_APPEND, "map_restart 0\n" );
  91. }
  92. /*
  93. =================
  94. UI_SPPostgameMenu_NextEvent
  95. =================
  96. */
  97. static void UI_SPPostgameMenu_NextEvent( void* ptr, int event ) {
  98. int currentSet;
  99. int levelSet;
  100. int level;
  101. int currentLevel;
  102. const char *arenaInfo;
  103. if (event != QM_ACTIVATED) {
  104. return;
  105. }
  106. UI_PopMenu();
  107. // handle specially if we just won the training map
  108. if( postgameMenuInfo.won == 0 ) {
  109. level = 0;
  110. }
  111. else {
  112. level = postgameMenuInfo.level + 1;
  113. }
  114. levelSet = level / ARENAS_PER_TIER;
  115. currentLevel = UI_GetCurrentGame();
  116. if( currentLevel == -1 ) {
  117. currentLevel = postgameMenuInfo.level;
  118. }
  119. currentSet = currentLevel / ARENAS_PER_TIER;
  120. if( levelSet > currentSet || levelSet == UI_GetNumSPTiers() ) {
  121. level = currentLevel;
  122. }
  123. arenaInfo = UI_GetArenaInfoByNumber( level );
  124. if ( !arenaInfo ) {
  125. return;
  126. }
  127. UI_SPArena_Start( arenaInfo );
  128. }
  129. /*
  130. =================
  131. UI_SPPostgameMenu_MenuEvent
  132. =================
  133. */
  134. static void UI_SPPostgameMenu_MenuEvent( void* ptr, int event )
  135. {
  136. if (event != QM_ACTIVATED) {
  137. return;
  138. }
  139. UI_PopMenu();
  140. trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect; levelselect\n" );
  141. }
  142. /*
  143. =================
  144. UI_SPPostgameMenu_MenuKey
  145. =================
  146. */
  147. static sfxHandle_t UI_SPPostgameMenu_MenuKey( int key ) {
  148. if ( uis.realtime < postgameMenuInfo.ignoreKeysTime ) {
  149. return 0;
  150. }
  151. if( postgameMenuInfo.phase == 1 ) {
  152. trap_Cmd_ExecuteText( EXEC_APPEND, "abort_podium\n" );
  153. postgameMenuInfo.phase = 2;
  154. postgameMenuInfo.starttime = uis.realtime;
  155. postgameMenuInfo.ignoreKeysTime = uis.realtime + 250;
  156. return 0;
  157. }
  158. if( postgameMenuInfo.phase == 2 ) {
  159. postgameMenuInfo.phase = 3;
  160. postgameMenuInfo.starttime = uis.realtime;
  161. postgameMenuInfo.ignoreKeysTime = uis.realtime + 250;
  162. return 0;
  163. }
  164. if( key == K_ESCAPE || key == K_MOUSE2 ) {
  165. return 0;
  166. }
  167. return Menu_DefaultKey( &postgameMenuInfo.menu, key );
  168. }
  169. static int medalLocations[6] = {144, 448, 88, 504, 32, 560};
  170. static void UI_SPPostgameMenu_DrawAwardsMedals( int max ) {
  171. int n;
  172. int medal;
  173. int amount;
  174. int x, y;
  175. char buf[16];
  176. for( n = 0; n < max; n++ ) {
  177. x = medalLocations[n];
  178. y = 64;
  179. medal = postgameMenuInfo.awardsEarned[n];
  180. amount = postgameMenuInfo.awardsLevels[n];
  181. UI_DrawNamedPic( x, y, 48, 48, ui_medalPicNames[medal] );
  182. if( medal == AWARD_ACCURACY ) {
  183. Com_sprintf( buf, sizeof(buf), "%i%%", amount );
  184. }
  185. else {
  186. if( amount == 1 ) {
  187. continue;
  188. }
  189. Com_sprintf( buf, sizeof(buf), "%i", amount );
  190. }
  191. UI_DrawString( x + 24, y + 52, buf, UI_CENTER, color_yellow );
  192. }
  193. }
  194. static void UI_SPPostgameMenu_DrawAwardsPresentation( int timer ) {
  195. int awardNum;
  196. int atimer;
  197. vec4_t color;
  198. awardNum = timer / AWARD_PRESENTATION_TIME;
  199. atimer = timer % AWARD_PRESENTATION_TIME;
  200. color[0] = color[1] = color[2] = 1.0f;
  201. color[3] = (float)( AWARD_PRESENTATION_TIME - atimer ) / (float)AWARD_PRESENTATION_TIME;
  202. UI_DrawProportionalString( 320, 64, ui_medalNames[postgameMenuInfo.awardsEarned[awardNum]], UI_CENTER, color );
  203. UI_SPPostgameMenu_DrawAwardsMedals( awardNum + 1 );
  204. if( !postgameMenuInfo.playedSound[awardNum] ) {
  205. postgameMenuInfo.playedSound[awardNum] = qtrue;
  206. trap_S_StartLocalSound( trap_S_RegisterSound( ui_medalSounds[postgameMenuInfo.awardsEarned[awardNum]], qfalse ), CHAN_ANNOUNCER );
  207. }
  208. }
  209. /*
  210. =================
  211. UI_SPPostgameMenu_MenuDrawScoreLine
  212. =================
  213. */
  214. static void UI_SPPostgameMenu_MenuDrawScoreLine( int n, int y ) {
  215. int rank;
  216. char name[64];
  217. char info[MAX_INFO_STRING];
  218. if( n > (postgameMenuInfo.numClients + 1) ) {
  219. n -= (postgameMenuInfo.numClients + 2);
  220. }
  221. if( n >= postgameMenuInfo.numClients ) {
  222. return;
  223. }
  224. rank = postgameMenuInfo.ranks[n];
  225. if( rank & RANK_TIED_FLAG ) {
  226. UI_DrawString( 640 - 31 * SMALLCHAR_WIDTH, y, "(tie)", UI_LEFT|UI_SMALLFONT, color_white );
  227. rank &= ~RANK_TIED_FLAG;
  228. }
  229. trap_GetConfigString( CS_PLAYERS + postgameMenuInfo.clientNums[n], info, MAX_INFO_STRING );
  230. Q_strncpyz( name, Info_ValueForKey( info, "n" ), sizeof(name) );
  231. Q_CleanStr( name );
  232. UI_DrawString( 640 - 25 * SMALLCHAR_WIDTH, y, va( "#%i: %-16s %2i", rank + 1, name, postgameMenuInfo.scores[n] ), UI_LEFT|UI_SMALLFONT, color_white );
  233. }
  234. /*
  235. =================
  236. UI_SPPostgameMenu_MenuDraw
  237. =================
  238. */
  239. static void UI_SPPostgameMenu_MenuDraw( void ) {
  240. int timer;
  241. int serverId;
  242. int n;
  243. char info[MAX_INFO_STRING];
  244. trap_GetConfigString( CS_SYSTEMINFO, info, sizeof(info) );
  245. serverId = atoi( Info_ValueForKey( info, "sv_serverid" ) );
  246. if( serverId != postgameMenuInfo.serverId ) {
  247. UI_PopMenu();
  248. return;
  249. }
  250. // phase 1
  251. if ( postgameMenuInfo.numClients > 2 ) {
  252. UI_DrawProportionalString( 510, 480 - 64 - PROP_HEIGHT, postgameMenuInfo.placeNames[2], UI_CENTER, color_white );
  253. }
  254. UI_DrawProportionalString( 130, 480 - 64 - PROP_HEIGHT, postgameMenuInfo.placeNames[1], UI_CENTER, color_white );
  255. UI_DrawProportionalString( 320, 480 - 64 - 2 * PROP_HEIGHT, postgameMenuInfo.placeNames[0], UI_CENTER, color_white );
  256. if( postgameMenuInfo.phase == 1 ) {
  257. timer = uis.realtime - postgameMenuInfo.starttime;
  258. if( timer >= 1000 && postgameMenuInfo.winnerSound ) {
  259. trap_S_StartLocalSound( postgameMenuInfo.winnerSound, CHAN_ANNOUNCER );
  260. postgameMenuInfo.winnerSound = 0;
  261. }
  262. if( timer < 5000 ) {
  263. return;
  264. }
  265. postgameMenuInfo.phase = 2;
  266. postgameMenuInfo.starttime = uis.realtime;
  267. }
  268. // phase 2
  269. if( postgameMenuInfo.phase == 2 ) {
  270. timer = uis.realtime - postgameMenuInfo.starttime;
  271. if( timer >= ( postgameMenuInfo.numAwards * AWARD_PRESENTATION_TIME ) ) {
  272. if( timer < 5000 ) {
  273. return;
  274. }
  275. postgameMenuInfo.phase = 3;
  276. postgameMenuInfo.starttime = uis.realtime;
  277. }
  278. else {
  279. UI_SPPostgameMenu_DrawAwardsPresentation( timer );
  280. }
  281. }
  282. // phase 3
  283. if( postgameMenuInfo.phase == 3 ) {
  284. if( uis.demoversion ) {
  285. if( postgameMenuInfo.won == 1 && UI_ShowTierVideo( 8 )) {
  286. trap_Cvar_Set( "nextmap", "" );
  287. trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect; cinematic demoEnd.RoQ\n" );
  288. return;
  289. }
  290. }
  291. else if( postgameMenuInfo.won > -1 && UI_ShowTierVideo( postgameMenuInfo.won + 1 )) {
  292. if( postgameMenuInfo.won == postgameMenuInfo.lastTier ) {
  293. trap_Cvar_Set( "nextmap", "" );
  294. trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect; cinematic end.RoQ\n" );
  295. return;
  296. }
  297. trap_Cvar_SetValue( "ui_spSelection", postgameMenuInfo.won * ARENAS_PER_TIER );
  298. trap_Cvar_Set( "nextmap", "levelselect" );
  299. trap_Cmd_ExecuteText( EXEC_APPEND, va( "disconnect; cinematic tier%i.RoQ\n", postgameMenuInfo.won + 1 ) );
  300. return;
  301. }
  302. postgameMenuInfo.item_again.generic.flags &= ~QMF_INACTIVE;
  303. postgameMenuInfo.item_next.generic.flags &= ~QMF_INACTIVE;
  304. postgameMenuInfo.item_menu.generic.flags &= ~QMF_INACTIVE;
  305. UI_SPPostgameMenu_DrawAwardsMedals( postgameMenuInfo.numAwards );
  306. Menu_Draw( &postgameMenuInfo.menu );
  307. }
  308. // draw the scoreboard
  309. if( !trap_Cvar_VariableValue( "ui_spScoreboard" ) ) {
  310. return;
  311. }
  312. timer = uis.realtime - postgameMenuInfo.scoreboardtime;
  313. if( postgameMenuInfo.numClients <= 3 ) {
  314. n = 0;
  315. }
  316. else {
  317. n = timer / 1500 % (postgameMenuInfo.numClients + 2);
  318. }
  319. UI_SPPostgameMenu_MenuDrawScoreLine( n, 0 );
  320. UI_SPPostgameMenu_MenuDrawScoreLine( n + 1, 0 + SMALLCHAR_HEIGHT );
  321. UI_SPPostgameMenu_MenuDrawScoreLine( n + 2, 0 + 2 * SMALLCHAR_HEIGHT );
  322. }
  323. /*
  324. =================
  325. UI_SPPostgameMenu_Cache
  326. =================
  327. */
  328. void UI_SPPostgameMenu_Cache( void ) {
  329. int n;
  330. qboolean buildscript;
  331. buildscript = trap_Cvar_VariableValue("com_buildscript");
  332. trap_R_RegisterShaderNoMip( ART_MENU0 );
  333. trap_R_RegisterShaderNoMip( ART_MENU1 );
  334. trap_R_RegisterShaderNoMip( ART_REPLAY0 );
  335. trap_R_RegisterShaderNoMip( ART_REPLAY1 );
  336. trap_R_RegisterShaderNoMip( ART_NEXT0 );
  337. trap_R_RegisterShaderNoMip( ART_NEXT1 );
  338. for( n = 0; n < 6; n++ ) {
  339. trap_R_RegisterShaderNoMip( ui_medalPicNames[n] );
  340. trap_S_RegisterSound( ui_medalSounds[n], qfalse );
  341. }
  342. if( buildscript ) {
  343. trap_S_RegisterSound( "music/loss.wav", qfalse );
  344. trap_S_RegisterSound( "music/win.wav", qfalse );
  345. trap_S_RegisterSound( "sound/player/announce/youwin.wav", qfalse );
  346. }
  347. }
  348. /*
  349. =================
  350. UI_SPPostgameMenu_Init
  351. =================
  352. */
  353. static void UI_SPPostgameMenu_Init( void ) {
  354. postgameMenuInfo.menu.wrapAround = qtrue;
  355. postgameMenuInfo.menu.key = UI_SPPostgameMenu_MenuKey;
  356. postgameMenuInfo.menu.draw = UI_SPPostgameMenu_MenuDraw;
  357. postgameMenuInfo.ignoreKeysTime = uis.realtime + 1500;
  358. UI_SPPostgameMenu_Cache();
  359. postgameMenuInfo.item_menu.generic.type = MTYPE_BITMAP;
  360. postgameMenuInfo.item_menu.generic.name = ART_MENU0;
  361. postgameMenuInfo.item_menu.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE;
  362. postgameMenuInfo.item_menu.generic.x = 0;
  363. postgameMenuInfo.item_menu.generic.y = 480-64;
  364. postgameMenuInfo.item_menu.generic.callback = UI_SPPostgameMenu_MenuEvent;
  365. postgameMenuInfo.item_menu.generic.id = ID_MENU;
  366. postgameMenuInfo.item_menu.width = 128;
  367. postgameMenuInfo.item_menu.height = 64;
  368. postgameMenuInfo.item_menu.focuspic = ART_MENU1;
  369. postgameMenuInfo.item_again.generic.type = MTYPE_BITMAP;
  370. postgameMenuInfo.item_again.generic.name = ART_REPLAY0;
  371. postgameMenuInfo.item_again.generic.flags = QMF_CENTER_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE;
  372. postgameMenuInfo.item_again.generic.x = 320;
  373. postgameMenuInfo.item_again.generic.y = 480-64;
  374. postgameMenuInfo.item_again.generic.callback = UI_SPPostgameMenu_AgainEvent;
  375. postgameMenuInfo.item_again.generic.id = ID_AGAIN;
  376. postgameMenuInfo.item_again.width = 128;
  377. postgameMenuInfo.item_again.height = 64;
  378. postgameMenuInfo.item_again.focuspic = ART_REPLAY1;
  379. postgameMenuInfo.item_next.generic.type = MTYPE_BITMAP;
  380. postgameMenuInfo.item_next.generic.name = ART_NEXT0;
  381. postgameMenuInfo.item_next.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE;
  382. postgameMenuInfo.item_next.generic.x = 640;
  383. postgameMenuInfo.item_next.generic.y = 480-64;
  384. postgameMenuInfo.item_next.generic.callback = UI_SPPostgameMenu_NextEvent;
  385. postgameMenuInfo.item_next.generic.id = ID_NEXT;
  386. postgameMenuInfo.item_next.width = 128;
  387. postgameMenuInfo.item_next.height = 64;
  388. postgameMenuInfo.item_next.focuspic = ART_NEXT1;
  389. Menu_AddItem( &postgameMenuInfo.menu, ( void * )&postgameMenuInfo.item_menu );
  390. Menu_AddItem( &postgameMenuInfo.menu, ( void * )&postgameMenuInfo.item_again );
  391. Menu_AddItem( &postgameMenuInfo.menu, ( void * )&postgameMenuInfo.item_next );
  392. }
  393. static void Prepname( int index ) {
  394. int len;
  395. char name[64];
  396. char info[MAX_INFO_STRING];
  397. trap_GetConfigString( CS_PLAYERS + postgameMenuInfo.clientNums[index], info, MAX_INFO_STRING );
  398. Q_strncpyz( name, Info_ValueForKey( info, "n" ), sizeof(name) );
  399. Q_CleanStr( name );
  400. len = strlen( name );
  401. while( len && UI_ProportionalStringWidth( name ) > 256 ) {
  402. len--;
  403. name[len] = 0;
  404. }
  405. Q_strncpyz( postgameMenuInfo.placeNames[index], name, sizeof(postgameMenuInfo.placeNames[index]) );
  406. }
  407. /*
  408. =================
  409. UI_SPPostgameMenu_f
  410. =================
  411. */
  412. void UI_SPPostgameMenu_f( void ) {
  413. int playerGameRank;
  414. int playerClientNum;
  415. int n;
  416. int oldFrags, newFrags;
  417. const char *arena;
  418. int awardValues[6];
  419. char map[MAX_QPATH];
  420. char info[MAX_INFO_STRING];
  421. memset( &postgameMenuInfo, 0, sizeof(postgameMenuInfo) );
  422. trap_GetConfigString( CS_SYSTEMINFO, info, sizeof(info) );
  423. postgameMenuInfo.serverId = atoi( Info_ValueForKey( info, "sv_serverid" ) );
  424. trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
  425. Q_strncpyz( map, Info_ValueForKey( info, "mapname" ), sizeof(map) );
  426. arena = UI_GetArenaInfoByMap( map );
  427. if ( !arena ) {
  428. return;
  429. }
  430. Q_strncpyz( arenainfo, arena, sizeof(arenainfo) );
  431. postgameMenuInfo.level = atoi( Info_ValueForKey( arenainfo, "num" ) );
  432. postgameMenuInfo.numClients = atoi( UI_Argv( 1 ) );
  433. playerClientNum = atoi( UI_Argv( 2 ) );
  434. playerGameRank = 8; // in case they ended game as a spectator
  435. if( postgameMenuInfo.numClients > MAX_SCOREBOARD_CLIENTS ) {
  436. postgameMenuInfo.numClients = MAX_SCOREBOARD_CLIENTS;
  437. }
  438. for( n = 0; n < postgameMenuInfo.numClients; n++ ) {
  439. postgameMenuInfo.clientNums[n] = atoi( UI_Argv( 8 + n * 3 + 1 ) );
  440. postgameMenuInfo.ranks[n] = atoi( UI_Argv( 8 + n * 3 + 2 ) );
  441. postgameMenuInfo.scores[n] = atoi( UI_Argv( 8 + n * 3 + 3 ) );
  442. if( postgameMenuInfo.clientNums[n] == playerClientNum ) {
  443. playerGameRank = (postgameMenuInfo.ranks[n] & ~RANK_TIED_FLAG) + 1;
  444. }
  445. }
  446. UI_SetBestScore( postgameMenuInfo.level, playerGameRank );
  447. // process award stats and prepare presentation data
  448. awardValues[AWARD_ACCURACY] = atoi( UI_Argv( 3 ) );
  449. awardValues[AWARD_IMPRESSIVE] = atoi( UI_Argv( 4 ) );
  450. awardValues[AWARD_EXCELLENT] = atoi( UI_Argv( 5 ) );
  451. awardValues[AWARD_GAUNTLET] = atoi( UI_Argv( 6 ) );
  452. awardValues[AWARD_FRAGS] = atoi( UI_Argv( 7 ) );
  453. awardValues[AWARD_PERFECT] = atoi( UI_Argv( 8 ) );
  454. postgameMenuInfo.numAwards = 0;
  455. if( awardValues[AWARD_ACCURACY] >= 50 ) {
  456. UI_LogAwardData( AWARD_ACCURACY, 1 );
  457. postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_ACCURACY;
  458. postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = awardValues[AWARD_ACCURACY];
  459. postgameMenuInfo.numAwards++;
  460. }
  461. if( awardValues[AWARD_IMPRESSIVE] ) {
  462. UI_LogAwardData( AWARD_IMPRESSIVE, awardValues[AWARD_IMPRESSIVE] );
  463. postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_IMPRESSIVE;
  464. postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = awardValues[AWARD_IMPRESSIVE];
  465. postgameMenuInfo.numAwards++;
  466. }
  467. if( awardValues[AWARD_EXCELLENT] ) {
  468. UI_LogAwardData( AWARD_EXCELLENT, awardValues[AWARD_EXCELLENT] );
  469. postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_EXCELLENT;
  470. postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = awardValues[AWARD_EXCELLENT];
  471. postgameMenuInfo.numAwards++;
  472. }
  473. if( awardValues[AWARD_GAUNTLET] ) {
  474. UI_LogAwardData( AWARD_GAUNTLET, awardValues[AWARD_GAUNTLET] );
  475. postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_GAUNTLET;
  476. postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = awardValues[AWARD_GAUNTLET];
  477. postgameMenuInfo.numAwards++;
  478. }
  479. oldFrags = UI_GetAwardLevel( AWARD_FRAGS ) / 100;
  480. UI_LogAwardData( AWARD_FRAGS, awardValues[AWARD_FRAGS] );
  481. newFrags = UI_GetAwardLevel( AWARD_FRAGS ) / 100;
  482. if( newFrags > oldFrags ) {
  483. postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_FRAGS;
  484. postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = newFrags * 100;
  485. postgameMenuInfo.numAwards++;
  486. }
  487. if( awardValues[AWARD_PERFECT] ) {
  488. UI_LogAwardData( AWARD_PERFECT, 1 );
  489. postgameMenuInfo.awardsEarned[postgameMenuInfo.numAwards] = AWARD_PERFECT;
  490. postgameMenuInfo.awardsLevels[postgameMenuInfo.numAwards] = 1;
  491. postgameMenuInfo.numAwards++;
  492. }
  493. if ( playerGameRank == 1 ) {
  494. postgameMenuInfo.won = UI_TierCompleted( postgameMenuInfo.level );
  495. }
  496. else {
  497. postgameMenuInfo.won = -1;
  498. }
  499. postgameMenuInfo.starttime = uis.realtime;
  500. postgameMenuInfo.scoreboardtime = uis.realtime;
  501. trap_Key_SetCatcher( KEYCATCH_UI );
  502. uis.menusp = 0;
  503. UI_SPPostgameMenu_Init();
  504. UI_PushMenu( &postgameMenuInfo.menu );
  505. if ( playerGameRank == 1 ) {
  506. Menu_SetCursorToItem( &postgameMenuInfo.menu, &postgameMenuInfo.item_next );
  507. }
  508. else {
  509. Menu_SetCursorToItem( &postgameMenuInfo.menu, &postgameMenuInfo.item_again );
  510. }
  511. Prepname( 0 );
  512. Prepname( 1 );
  513. Prepname( 2 );
  514. if ( playerGameRank != 1 ) {
  515. postgameMenuInfo.winnerSound = trap_S_RegisterSound( va( "sound/player/announce/%s_wins.wav", postgameMenuInfo.placeNames[0] ), qfalse );
  516. trap_Cmd_ExecuteText( EXEC_APPEND, "music music/loss\n" );
  517. }
  518. else {
  519. postgameMenuInfo.winnerSound = trap_S_RegisterSound( "sound/player/announce/youwin.wav", qfalse );
  520. trap_Cmd_ExecuteText( EXEC_APPEND, "music music/win\n" );
  521. }
  522. postgameMenuInfo.phase = 1;
  523. postgameMenuInfo.lastTier = UI_GetNumSPTiers();
  524. if ( UI_GetSpecialArenaInfo( "final" ) ) {
  525. postgameMenuInfo.lastTier++;
  526. }
  527. }