Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

ui_sppostgame.c (18879B)


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