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 Quake III Arena source code; 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 // gameinfo.c
25 //
26 
27 #include "ui_local.h"
28 
29 
30 //
31 // arena and bot info
32 //
33 
34 #define POOLSIZE	128 * 1024
35 
36 int				ui_numBots;
37 static char		*ui_botInfos[MAX_BOTS];
38 
39 static int		ui_numArenas;
40 static char		*ui_arenaInfos[MAX_ARENAS];
41 
42 static int		ui_numSinglePlayerArenas;
43 static int		ui_numSpecialSinglePlayerArenas;
44 
45 static char		memoryPool[POOLSIZE];
46 static int		allocPoint, outOfMemory;
47 
48 
49 /*
50 ===============
51 UI_Alloc
52 ===============
53 */
UI_Alloc(int size)54 void *UI_Alloc( int size ) {
55 	char	*p;
56 
57 	if ( allocPoint + size > POOLSIZE ) {
58 		outOfMemory = qtrue;
59 		return NULL;
60 	}
61 
62 	p = &memoryPool[allocPoint];
63 
64 	allocPoint += ( size + 31 ) & ~31;
65 
66 	return p;
67 }
68 
69 /*
70 ===============
71 UI_InitMemory
72 ===============
73 */
UI_InitMemory(void)74 void UI_InitMemory( void ) {
75 	allocPoint = 0;
76 	outOfMemory = qfalse;
77 }
78 
79 /*
80 ===============
81 UI_ParseInfos
82 ===============
83 */
UI_ParseInfos(char * buf,int max,char * infos[])84 int UI_ParseInfos( char *buf, int max, char *infos[] ) {
85 	char	*token;
86 	int		count;
87 	char	key[MAX_TOKEN_CHARS];
88 	char	info[MAX_INFO_STRING];
89 
90 	count = 0;
91 
92 	while ( 1 ) {
93 		token = COM_Parse( &buf );
94 		if ( !token[0] ) {
95 			break;
96 		}
97 		if ( strcmp( token, "{" ) ) {
98 			Com_Printf( "Missing { in info file\n" );
99 			break;
100 		}
101 
102 		if ( count == max ) {
103 			Com_Printf( "Max infos exceeded\n" );
104 			break;
105 		}
106 
107 		info[0] = '\0';
108 		while ( 1 ) {
109 			token = COM_ParseExt( &buf, qtrue );
110 			if ( !token[0] ) {
111 				Com_Printf( "Unexpected end of info file\n" );
112 				break;
113 			}
114 			if ( !strcmp( token, "}" ) ) {
115 				break;
116 			}
117 			Q_strncpyz( key, token, sizeof( key ) );
118 
119 			token = COM_ParseExt( &buf, qfalse );
120 			if ( !token[0] ) {
121 				strcpy( token, "<NULL>" );
122 			}
123 			Info_SetValueForKey( info, key, token );
124 		}
125 		//NOTE: extra space for arena number
126 		infos[count] = UI_Alloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1);
127 		if (infos[count]) {
128 			strcpy(infos[count], info);
129 			count++;
130 		}
131 	}
132 	return count;
133 }
134 
135 /*
136 ===============
137 UI_LoadArenasFromFile
138 ===============
139 */
UI_LoadArenasFromFile(char * filename)140 static void UI_LoadArenasFromFile( char *filename ) {
141 	int				len;
142 	fileHandle_t	f;
143 	char			buf[MAX_ARENAS_TEXT];
144 
145 	len = trap_FS_FOpenFile( filename, &f, FS_READ );
146 	if ( !f ) {
147 		trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
148 		return;
149 	}
150 	if ( len >= MAX_ARENAS_TEXT ) {
151 		trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_ARENAS_TEXT ) );
152 		trap_FS_FCloseFile( f );
153 		return;
154 	}
155 
156 	trap_FS_Read( buf, len, f );
157 	buf[len] = 0;
158 	trap_FS_FCloseFile( f );
159 
160 	ui_numArenas += UI_ParseInfos( buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas] );
161 }
162 
163 /*
164 ===============
165 UI_LoadArenas
166 ===============
167 */
UI_LoadArenas(void)168 static void UI_LoadArenas( void ) {
169 	int			numdirs;
170 	vmCvar_t	arenasFile;
171 	char		filename[128];
172 	char		dirlist[1024];
173 	char*		dirptr;
174 	int			i, n;
175 	int			dirlen;
176 	char		*type;
177 	char		*tag;
178 	int			singlePlayerNum, specialNum, otherNum;
179 
180 	ui_numArenas = 0;
181 
182 	trap_Cvar_Register( &arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM );
183 	if( *arenasFile.string ) {
184 		UI_LoadArenasFromFile(arenasFile.string);
185 	}
186 	else {
187 		UI_LoadArenasFromFile("scripts/arenas.txt");
188 	}
189 
190 	// get all arenas from .arena files
191 	numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, 1024 );
192 	dirptr  = dirlist;
193 	for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
194 		dirlen = strlen(dirptr);
195 		strcpy(filename, "scripts/");
196 		strcat(filename, dirptr);
197 		UI_LoadArenasFromFile(filename);
198 	}
199 	trap_Print( va( "%i arenas parsed\n", ui_numArenas ) );
200 	if (outOfMemory) trap_Print(S_COLOR_YELLOW"WARNING: not anough memory in pool to load all arenas\n");
201 
202 	// set initial numbers
203 	for( n = 0; n < ui_numArenas; n++ ) {
204 		Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", n ) );
205 	}
206 
207 	// go through and count single players levels
208 	ui_numSinglePlayerArenas = 0;
209 	ui_numSpecialSinglePlayerArenas = 0;
210 	for( n = 0; n < ui_numArenas; n++ ) {
211 		// determine type
212 		type = Info_ValueForKey( ui_arenaInfos[n], "type" );
213 
214 		// if no type specified, it will be treated as "ffa"
215 		if( !*type ) {
216 			continue;
217 		}
218 
219 		if( strstr( type, "single" ) ) {
220 			// check for special single player arenas (training, final)
221 			tag = Info_ValueForKey( ui_arenaInfos[n], "special" );
222 			if( *tag ) {
223 				ui_numSpecialSinglePlayerArenas++;
224 				continue;
225 			}
226 
227 			ui_numSinglePlayerArenas++;
228 		}
229 	}
230 
231 	n = ui_numSinglePlayerArenas % ARENAS_PER_TIER;
232 	if( n != 0 ) {
233 		ui_numSinglePlayerArenas -= n;
234 		trap_Print( va( "%i arenas ignored to make count divisible by %i\n", n, ARENAS_PER_TIER ) );
235 	}
236 
237 	// go through once more and assign number to the levels
238 	singlePlayerNum = 0;
239 	specialNum = singlePlayerNum + ui_numSinglePlayerArenas;
240 	otherNum = specialNum + ui_numSpecialSinglePlayerArenas;
241 	for( n = 0; n < ui_numArenas; n++ ) {
242 		// determine type
243 		type = Info_ValueForKey( ui_arenaInfos[n], "type" );
244 
245 		// if no type specified, it will be treated as "ffa"
246 		if( *type ) {
247 			if( strstr( type, "single" ) ) {
248 				// check for special single player arenas (training, final)
249 				tag = Info_ValueForKey( ui_arenaInfos[n], "special" );
250 				if( *tag ) {
251 					Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", specialNum++ ) );
252 					continue;
253 				}
254 
255 				Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", singlePlayerNum++ ) );
256 				continue;
257 			}
258 		}
259 
260 		Info_SetValueForKey( ui_arenaInfos[n], "num", va( "%i", otherNum++ ) );
261 	}
262 }
263 
264 /*
265 ===============
266 UI_GetArenaInfoByNumber
267 ===============
268 */
UI_GetArenaInfoByNumber(int num)269 const char *UI_GetArenaInfoByNumber( int num ) {
270 	int		n;
271 	char	*value;
272 
273 	if( num < 0 || num >= ui_numArenas ) {
274 		trap_Print( va( S_COLOR_RED "Invalid arena number: %i\n", num ) );
275 		return NULL;
276 	}
277 
278 	for( n = 0; n < ui_numArenas; n++ ) {
279 		value = Info_ValueForKey( ui_arenaInfos[n], "num" );
280 		if( *value && atoi(value) == num ) {
281 			return ui_arenaInfos[n];
282 		}
283 	}
284 
285 	return NULL;
286 }
287 
288 
289 /*
290 ===============
291 UI_GetArenaInfoByNumber
292 ===============
293 */
UI_GetArenaInfoByMap(const char * map)294 const char *UI_GetArenaInfoByMap( const char *map ) {
295 	int			n;
296 
297 	for( n = 0; n < ui_numArenas; n++ ) {
298 		if( Q_stricmp( Info_ValueForKey( ui_arenaInfos[n], "map" ), map ) == 0 ) {
299 			return ui_arenaInfos[n];
300 		}
301 	}
302 
303 	return NULL;
304 }
305 
306 
307 /*
308 ===============
309 UI_GetSpecialArenaInfo
310 ===============
311 */
UI_GetSpecialArenaInfo(const char * tag)312 const char *UI_GetSpecialArenaInfo( const char *tag ) {
313 	int			n;
314 
315 	for( n = 0; n < ui_numArenas; n++ ) {
316 		if( Q_stricmp( Info_ValueForKey( ui_arenaInfos[n], "special" ), tag ) == 0 ) {
317 			return ui_arenaInfos[n];
318 		}
319 	}
320 
321 	return NULL;
322 }
323 
324 /*
325 ===============
326 UI_LoadBotsFromFile
327 ===============
328 */
UI_LoadBotsFromFile(char * filename)329 static void UI_LoadBotsFromFile( char *filename ) {
330 	int				len;
331 	fileHandle_t	f;
332 	char			buf[MAX_BOTS_TEXT];
333 
334 	len = trap_FS_FOpenFile( filename, &f, FS_READ );
335 	if ( !f ) {
336 		trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
337 		return;
338 	}
339 	if ( len >= MAX_BOTS_TEXT ) {
340 		trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_BOTS_TEXT ) );
341 		trap_FS_FCloseFile( f );
342 		return;
343 	}
344 
345 	trap_FS_Read( buf, len, f );
346 	buf[len] = 0;
347 	trap_FS_FCloseFile( f );
348 
349 	ui_numBots += UI_ParseInfos( buf, MAX_BOTS - ui_numBots, &ui_botInfos[ui_numBots] );
350 	if (outOfMemory) trap_Print(S_COLOR_YELLOW"WARNING: not anough memory in pool to load all bots\n");
351 }
352 
353 /*
354 ===============
355 UI_LoadBots
356 ===============
357 */
UI_LoadBots(void)358 static void UI_LoadBots( void ) {
359 	vmCvar_t	botsFile;
360 	int			numdirs;
361 	char		filename[128];
362 	char		dirlist[1024];
363 	char*		dirptr;
364 	int			i;
365 	int			dirlen;
366 
367 	ui_numBots = 0;
368 
369 	trap_Cvar_Register( &botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM );
370 	if( *botsFile.string ) {
371 		UI_LoadBotsFromFile(botsFile.string);
372 	}
373 	else {
374 		UI_LoadBotsFromFile("scripts/bots.txt");
375 	}
376 
377 	// get all bots from .bot files
378 	numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, 1024 );
379 	dirptr  = dirlist;
380 	for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
381 		dirlen = strlen(dirptr);
382 		strcpy(filename, "scripts/");
383 		strcat(filename, dirptr);
384 		UI_LoadBotsFromFile(filename);
385 	}
386 	trap_Print( va( "%i bots parsed\n", ui_numBots ) );
387 }
388 
389 
390 /*
391 ===============
392 UI_GetBotInfoByNumber
393 ===============
394 */
UI_GetBotInfoByNumber(int num)395 char *UI_GetBotInfoByNumber( int num ) {
396 	if( num < 0 || num >= ui_numBots ) {
397 		trap_Print( va( S_COLOR_RED "Invalid bot number: %i\n", num ) );
398 		return NULL;
399 	}
400 	return ui_botInfos[num];
401 }
402 
403 
404 /*
405 ===============
406 UI_GetBotInfoByName
407 ===============
408 */
UI_GetBotInfoByName(const char * name)409 char *UI_GetBotInfoByName( const char *name ) {
410 	int		n;
411 	char	*value;
412 
413 	for ( n = 0; n < ui_numBots ; n++ ) {
414 		value = Info_ValueForKey( ui_botInfos[n], "name" );
415 		if ( !Q_stricmp( value, name ) ) {
416 			return ui_botInfos[n];
417 		}
418 	}
419 
420 	return NULL;
421 }
422 
423 
424 //
425 // single player game info
426 //
427 
428 /*
429 ===============
430 UI_GetBestScore
431 
432 Returns the player's best finish on a given level, 0 if the have not played the level
433 ===============
434 */
UI_GetBestScore(int level,int * score,int * skill)435 void UI_GetBestScore( int level, int *score, int *skill ) {
436 	int		n;
437 	int		skillScore;
438 	int		bestScore;
439 	int		bestScoreSkill;
440 	char	arenaKey[16];
441 	char	scores[MAX_INFO_VALUE];
442 
443 	if( !score || !skill ) {
444 		return;
445 	}
446 
447 	if( level < 0 || level > ui_numArenas ) {
448 		return;
449 	}
450 
451 	bestScore = 0;
452 	bestScoreSkill = 0;
453 
454 	for( n = 1; n <= 5; n++ ) {
455 		trap_Cvar_VariableStringBuffer( va( "g_spScores%i", n ), scores, MAX_INFO_VALUE );
456 
457 		Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level );
458 		skillScore = atoi( Info_ValueForKey( scores, arenaKey ) );
459 
460 		if( skillScore < 1 || skillScore > 8 ) {
461 			continue;
462 		}
463 
464 		if( !bestScore || skillScore <= bestScore ) {
465 			bestScore = skillScore;
466 			bestScoreSkill = n;
467 		}
468 	}
469 
470 	*score = bestScore;
471 	*skill = bestScoreSkill;
472 }
473 
474 
475 /*
476 ===============
477 UI_SetBestScore
478 
479 Set the player's best finish for a level
480 ===============
481 */
UI_SetBestScore(int level,int score)482 void UI_SetBestScore( int level, int score ) {
483 	int		skill;
484 	int		oldScore;
485 	char	arenaKey[16];
486 	char	scores[MAX_INFO_VALUE];
487 
488 	// validate score
489 	if( score < 1 || score > 8 ) {
490 		return;
491 	}
492 
493 	// validate skill
494 	skill = (int)trap_Cvar_VariableValue( "g_spSkill" );
495 	if( skill < 1 || skill > 5 ) {
496 		return;
497 	}
498 
499 	// get scores
500 	trap_Cvar_VariableStringBuffer( va( "g_spScores%i", skill ), scores, MAX_INFO_VALUE );
501 
502 	// see if this is better
503 	Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level );
504 	oldScore = atoi( Info_ValueForKey( scores, arenaKey ) );
505 	if( oldScore && oldScore <= score ) {
506 		return;
507 	}
508 
509 	// update scores
510 	Info_SetValueForKey( scores, arenaKey, va( "%i", score ) );
511 	trap_Cvar_Set( va( "g_spScores%i", skill ), scores );
512 }
513 
514 
515 /*
516 ===============
517 UI_LogAwardData
518 ===============
519 */
UI_LogAwardData(int award,int data)520 void UI_LogAwardData( int award, int data ) {
521 	char	key[16];
522 	char	awardData[MAX_INFO_VALUE];
523 	int		oldValue;
524 
525 	if( data == 0 ) {
526 		return;
527 	}
528 
529 	if( award > AWARD_PERFECT ) {
530 		trap_Print( va( S_COLOR_RED "Bad award %i in UI_LogAwardData\n", award ) );
531 		return;
532 	}
533 
534 	trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, sizeof(awardData) );
535 
536 	Com_sprintf( key, sizeof(key), "a%i", award );
537 	oldValue = atoi( Info_ValueForKey( awardData, key ) );
538 
539 	Info_SetValueForKey( awardData, key, va( "%i", oldValue + data ) );
540 	trap_Cvar_Set( "g_spAwards", awardData );
541 }
542 
543 
544 /*
545 ===============
546 UI_GetAwardLevel
547 ===============
548 */
UI_GetAwardLevel(int award)549 int UI_GetAwardLevel( int award ) {
550 	char	key[16];
551 	char	awardData[MAX_INFO_VALUE];
552 
553 	trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, sizeof(awardData) );
554 
555 	Com_sprintf( key, sizeof(key), "a%i", award );
556 	return atoi( Info_ValueForKey( awardData, key ) );
557 }
558 
559 
560 /*
561 ===============
562 UI_TierCompleted
563 ===============
564 */
UI_TierCompleted(int levelWon)565 int UI_TierCompleted( int levelWon ) {
566 	int			level;
567 	int			n;
568 	int			tier;
569 	int			score;
570 	int			skill;
571 	const char	*info;
572 
573 	tier = levelWon / ARENAS_PER_TIER;
574 	level = tier * ARENAS_PER_TIER;
575 
576 	if( tier == UI_GetNumSPTiers() ) {
577 		info = UI_GetSpecialArenaInfo( "training" );
578 		if( levelWon == atoi( Info_ValueForKey( info, "num" ) ) ) {
579 			return 0;
580 		}
581 		info = UI_GetSpecialArenaInfo( "final" );
582 		if( !info || levelWon == atoi( Info_ValueForKey( info, "num" ) ) ) {
583 			return tier + 1;
584 		}
585 		return -1;
586 	}
587 
588 	for( n = 0; n < ARENAS_PER_TIER; n++, level++ ) {
589 		UI_GetBestScore( level, &score, &skill );
590 		if ( score != 1 ) {
591 			return -1;
592 		}
593 	}
594 	return tier + 1;
595 }
596 
597 
598 /*
599 ===============
600 UI_ShowTierVideo
601 ===============
602 */
UI_ShowTierVideo(int tier)603 qboolean UI_ShowTierVideo( int tier ) {
604 	char	key[16];
605 	char	videos[MAX_INFO_VALUE];
606 
607 	if( tier <= 0 ) {
608 		return qfalse;
609 	}
610 
611 	trap_Cvar_VariableStringBuffer( "g_spVideos", videos, sizeof(videos) );
612 
613 	Com_sprintf( key, sizeof(key), "tier%i", tier );
614 	if( atoi( Info_ValueForKey( videos, key ) ) ) {
615 		return qfalse;
616 	}
617 
618 	Info_SetValueForKey( videos, key, va( "%i", 1 ) );
619 	trap_Cvar_Set( "g_spVideos", videos );
620 
621 	return qtrue;
622 }
623 
624 
625 /*
626 ===============
627 UI_CanShowTierVideo
628 ===============
629 */
UI_CanShowTierVideo(int tier)630 qboolean UI_CanShowTierVideo( int tier ) {
631 	char	key[16];
632 	char	videos[MAX_INFO_VALUE];
633 
634 	if( !tier ) {
635 		return qfalse;
636 	}
637 
638 	if( uis.demoversion && tier != 8 ) {
639 		return qfalse;
640 	}
641 
642 	trap_Cvar_VariableStringBuffer( "g_spVideos", videos, sizeof(videos) );
643 
644 	Com_sprintf( key, sizeof(key), "tier%i", tier );
645 	if( atoi( Info_ValueForKey( videos, key ) ) ) {
646 		return qtrue;
647 	}
648 
649 	return qfalse;
650 }
651 
652 
653 /*
654 ===============
655 UI_GetCurrentGame
656 
657 Returns the next level the player has not won
658 ===============
659 */
UI_GetCurrentGame(void)660 int UI_GetCurrentGame( void ) {
661 	int		level;
662 	int		rank;
663 	int		skill;
664 	const char *info;
665 
666 	info = UI_GetSpecialArenaInfo( "training" );
667 	if( info ) {
668 		level = atoi( Info_ValueForKey( info, "num" ) );
669 		UI_GetBestScore( level, &rank, &skill );
670 		if ( !rank || rank > 1 ) {
671 			return level;
672 		}
673 	}
674 
675 	for( level = 0; level < ui_numSinglePlayerArenas; level++ ) {
676 		UI_GetBestScore( level, &rank, &skill );
677 		if ( !rank || rank > 1 ) {
678 			return level;
679 		}
680 	}
681 
682 	info = UI_GetSpecialArenaInfo( "final" );
683 	if( !info ) {
684 		return -1;
685 	}
686 	return atoi( Info_ValueForKey( info, "num" ) );
687 }
688 
689 
690 /*
691 ===============
692 UI_NewGame
693 
694 Clears the scores and sets the difficutly level
695 ===============
696 */
UI_NewGame(void)697 void UI_NewGame( void ) {
698 	trap_Cvar_Set( "g_spScores1", "" );
699 	trap_Cvar_Set( "g_spScores2", "" );
700 	trap_Cvar_Set( "g_spScores3", "" );
701 	trap_Cvar_Set( "g_spScores4", "" );
702 	trap_Cvar_Set( "g_spScores5", "" );
703 	trap_Cvar_Set( "g_spAwards", "" );
704 	trap_Cvar_Set( "g_spVideos", "" );
705 }
706 
707 
708 /*
709 ===============
710 UI_GetNumArenas
711 ===============
712 */
UI_GetNumArenas(void)713 int UI_GetNumArenas( void ) {
714 	return ui_numArenas;
715 }
716 
717 
718 /*
719 ===============
720 UI_GetNumSPArenas
721 ===============
722 */
UI_GetNumSPArenas(void)723 int UI_GetNumSPArenas( void ) {
724 	return ui_numSinglePlayerArenas;
725 }
726 
727 
728 /*
729 ===============
730 UI_GetNumSPTiers
731 ===============
732 */
UI_GetNumSPTiers(void)733 int UI_GetNumSPTiers( void ) {
734 	return ui_numSinglePlayerArenas / ARENAS_PER_TIER;
735 }
736 
737 
738 /*
739 ===============
740 UI_GetNumBots
741 ===============
742 */
UI_GetNumBots(void)743 int UI_GetNumBots( void ) {
744 	return ui_numBots;
745 }
746 
747 
748 /*
749 ===============
750 UI_SPUnlock_f
751 ===============
752 */
UI_SPUnlock_f(void)753 void UI_SPUnlock_f( void ) {
754 	char	arenaKey[16];
755 	char	scores[MAX_INFO_VALUE];
756 	int		level;
757 	int		tier;
758 
759 	// get scores for skill 1
760 	trap_Cvar_VariableStringBuffer( "g_spScores1", scores, MAX_INFO_VALUE );
761 
762 	// update scores
763 	for( level = 0; level < ui_numSinglePlayerArenas + ui_numSpecialSinglePlayerArenas; level++ ) {
764 		Com_sprintf( arenaKey, sizeof( arenaKey ), "l%i", level );
765 		Info_SetValueForKey( scores, arenaKey, "1" );
766 	}
767 	trap_Cvar_Set( "g_spScores1", scores );
768 
769 	// unlock cinematics
770 	for( tier = 1; tier <= 8; tier++ ) {
771 		UI_ShowTierVideo( tier );
772 	}
773 
774 	trap_Print( "All levels unlocked at skill level 1\n" );
775 
776 	UI_SPLevelMenu_ReInit();
777 }
778 
779 
780 /*
781 ===============
782 UI_SPUnlockMedals_f
783 ===============
784 */
UI_SPUnlockMedals_f(void)785 void UI_SPUnlockMedals_f( void ) {
786 	int		n;
787 	char	key[16];
788 	char	awardData[MAX_INFO_VALUE];
789 
790 	trap_Cvar_VariableStringBuffer( "g_spAwards", awardData, MAX_INFO_VALUE );
791 
792 	for( n = 0; n < 6; n++ ) {
793 		Com_sprintf( key, sizeof(key), "a%i", n );
794 		Info_SetValueForKey( awardData, key, "100" );
795 	}
796 
797 	trap_Cvar_Set( "g_spAwards", awardData );
798 
799 	trap_Print( "All levels unlocked at 100\n" );
800 }
801 
802 
803 /*
804 ===============
805 UI_InitGameinfo
806 ===============
807 */
UI_InitGameinfo(void)808 void UI_InitGameinfo( void ) {
809 
810 	UI_InitMemory();
811 	UI_LoadArenas();
812 	UI_LoadBots();
813 
814 	uis.demoversion = qfalse;
815 }
816