1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein multiplayer GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
8 
9 RTCW MP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 RTCW MP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with RTCW MP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW MP 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 RTCW MP Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 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.
25 
26 ===========================================================================
27 */
28 
29 // Copyright (C) 1999-2000 Id Software, Inc.
30 //
31 //
32 // gameinfo.c
33 //
34 
35 #include "ui_local.h"
36 
37 
38 //
39 // arena and bot info
40 //
41 
42 
43 int ui_numBots;
44 static char     *ui_botInfos[MAX_BOTS];
45 
46 static int ui_numArenas;
47 static char     *ui_arenaInfos[MAX_ARENAS];
48 
49 //static int		ui_numSinglePlayerArenas; // TTimo: unused
50 //static int		ui_numSpecialSinglePlayerArenas; // TTimo: unused
51 
52 /*
53 ===============
54 UI_ParseInfos
55 ===============
56 */
UI_ParseInfos(char * buf,int max,char * infos[])57 int UI_ParseInfos( char *buf, int max, char *infos[] ) {
58 	char    *token;
59 	int count;
60 	char key[MAX_TOKEN_CHARS];
61 	char info[MAX_INFO_STRING];
62 
63 	count = 0;
64 
65 	while ( 1 ) {
66 		token = COM_Parse( &buf );
67 		if ( !token[0] ) {
68 			break;
69 		}
70 		if ( strcmp( token, "{" ) ) {
71 			Com_Printf( "Missing { in info file\n" );
72 			break;
73 		}
74 
75 		if ( count == max ) {
76 			Com_Printf( "Max infos exceeded\n" );
77 			break;
78 		}
79 
80 		info[0] = '\0';
81 		while ( 1 ) {
82 			token = COM_ParseExt( &buf, qtrue );
83 			if ( !token[0] ) {
84 				Com_Printf( "Unexpected end of info file\n" );
85 				break;
86 			}
87 			if ( !strcmp( token, "}" ) ) {
88 				break;
89 			}
90 			Q_strncpyz( key, token, sizeof( key ) );
91 
92 			token = COM_ParseExt( &buf, qfalse );
93 			if ( !token[0] ) {
94 				strcpy( token, "<NULL>" );
95 			}
96 			Info_SetValueForKey( info, key, token );
97 		}
98 		//NOTE: extra space for arena number
99 		infos[count] = UI_Alloc( strlen( info ) + strlen( "\\num\\" ) + strlen( va( "%d", MAX_ARENAS ) ) + 1 );
100 		if ( infos[count] ) {
101 			strcpy( infos[count], info );
102 			count++;
103 		}
104 	}
105 	return count;
106 }
107 
108 /*
109 ===============
110 UI_LoadArenasFromFile
111 ===============
112 */
UI_LoadArenasFromFile(char * filename)113 static void UI_LoadArenasFromFile( char *filename ) {
114 	int len;
115 	fileHandle_t f;
116 	char buf[MAX_ARENAS_TEXT];
117 
118 	len = trap_FS_FOpenFile( filename, &f, FS_READ );
119 	if ( !f ) {
120 		trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
121 		return;
122 	}
123 	if ( len >= MAX_ARENAS_TEXT ) {
124 		trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i\n", filename, len, MAX_ARENAS_TEXT ) );
125 		trap_FS_FCloseFile( f );
126 		return;
127 	}
128 
129 	trap_FS_Read( buf, len, f );
130 	buf[len] = 0;
131 	trap_FS_FCloseFile( f );
132 
133 	ui_numArenas += UI_ParseInfos( buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas] );
134 }
135 
136 /*
137 ===============
138 UI_LoadArenas
139 ===============
140 */
UI_LoadArenas(void)141 void UI_LoadArenas( void ) {
142 	int numdirs;
143 //	vmCvar_t	arenasFile;
144 	char filename[128];
145 	char dirlist[1024];
146 	char*       dirptr;
147 	int i;
148 	int dirlen;
149 
150 	ui_numArenas = 0;
151 
152 /*	NERVE - SMF - commented out
153 	trap_Cvar_Register( &arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM );
154 	if( *arenasFile.string ) {
155 		UI_LoadArenasFromFile(arenasFile.string);
156 	}
157 	else {
158 		UI_LoadArenasFromFile("scripts/arenas.txt");
159 	}
160 */
161 	// get all arenas from .arena files
162 	numdirs = trap_FS_GetFileList( "scripts", ".arena", dirlist, 1024 );
163 	dirptr  = dirlist;
164 	for ( i = 0; i < numdirs; i++, dirptr += dirlen + 1 ) {
165 		dirlen = strlen( dirptr );
166 		strcpy( filename, "scripts/" );
167 		strcat( filename, dirptr );
168 		UI_LoadArenasFromFile( filename );
169 	}
170 //	trap_DPrint( va( "%i arenas parsed\n", ui_numArenas ) ); // JPW NERVE pulled per atvi req
171 	if ( UI_OutOfMemory() ) {
172 		trap_Print( S_COLOR_YELLOW "WARNING: not enough memory in pool to load all arenas\n" );
173 	}
174 }
175 
176 /*
177 ===============
178 UI_LoadArenasIntoMapList
179 ===============
180 */
UI_LoadArenasIntoMapList(void)181 void UI_LoadArenasIntoMapList( void ) {
182 	int n;
183 	char *type, *str;
184 
185 	uiInfo.mapCount = 0;
186 
187 	for ( n = 0; n < ui_numArenas; n++ ) {
188 		// determine type
189 
190 		uiInfo.mapList[uiInfo.mapCount].cinematic = -1;
191 		uiInfo.mapList[uiInfo.mapCount].mapLoadName = String_Alloc( Info_ValueForKey( ui_arenaInfos[n], "map" ) );
192 		uiInfo.mapList[uiInfo.mapCount].mapName = String_Alloc( Info_ValueForKey( ui_arenaInfos[n], "longname" ) );
193 		uiInfo.mapList[uiInfo.mapCount].levelShot = -1;
194 		uiInfo.mapList[uiInfo.mapCount].imageName = String_Alloc( va( "levelshots/%s", uiInfo.mapList[uiInfo.mapCount].mapLoadName ) );
195 		uiInfo.mapList[uiInfo.mapCount].typeBits = 0;
196 
197 		// NERVE - SMF
198 		// set timelimit
199 		str = Info_ValueForKey( ui_arenaInfos[n], "Timelimit" );
200 		if ( *str ) {
201 			uiInfo.mapList[uiInfo.mapCount].Timelimit = atoi( str );
202 		} else {
203 			uiInfo.mapList[uiInfo.mapCount].Timelimit = 0;
204 		}
205 
206 		// set axis respawn time
207 		str = Info_ValueForKey( ui_arenaInfos[n], "AxisRespawnTime" );
208 		if ( *str ) {
209 			uiInfo.mapList[uiInfo.mapCount].AxisRespawnTime = atoi( str );
210 		} else {
211 			uiInfo.mapList[uiInfo.mapCount].AxisRespawnTime = 0;
212 		}
213 
214 		// set allied respawn time
215 		str = Info_ValueForKey( ui_arenaInfos[n], "AlliedRespawnTime" );
216 		if ( *str ) {
217 			uiInfo.mapList[uiInfo.mapCount].AlliedRespawnTime = atoi( str );
218 		} else {
219 			uiInfo.mapList[uiInfo.mapCount].AlliedRespawnTime = 0;
220 		}
221 		// -NERVE - SMF
222 
223 		type = Info_ValueForKey( ui_arenaInfos[n], "type" );
224 		// if no type specified, it will be treated as "ffa"
225 		if ( *type ) {
226 			if ( strstr( type, "ffa" ) ) {
227 				uiInfo.mapList[uiInfo.mapCount].typeBits |= ( 1 << GT_FFA );
228 			}
229 			if ( strstr( type, "tourney" ) ) {
230 				uiInfo.mapList[uiInfo.mapCount].typeBits |= ( 1 << GT_TOURNAMENT );
231 			}
232 			if ( strstr( type, "ctf" ) ) {
233 				uiInfo.mapList[uiInfo.mapCount].typeBits |= ( 1 << GT_CTF );
234 			}
235 			// NERVE - SMF
236 			if ( strstr( type, "wolfmp" ) ) {
237 				uiInfo.mapList[uiInfo.mapCount].typeBits |= ( 1 << GT_WOLF );
238 			}
239 			if ( strstr( type, "wolfsw" ) ) {
240 				uiInfo.mapList[uiInfo.mapCount].typeBits |= ( 1 << GT_WOLF_STOPWATCH );
241 			}
242 			if ( strstr( type, "wolfcp" ) ) {
243 				uiInfo.mapList[uiInfo.mapCount].typeBits |= ( 1 << GT_WOLF_CP );
244 			}
245 			// -NERVE - SMF
246 #ifdef MISSIONPACK
247 			if ( strstr( type, "oneflag" ) ) {
248 				uiInfo.mapList[uiInfo.mapCount].typeBits |= ( 1 << GT_1FCTF );
249 			}
250 			if ( strstr( type, "overload" ) ) {
251 				uiInfo.mapList[uiInfo.mapCount].typeBits |= ( 1 << GT_OBELISK );
252 			}
253 			if ( strstr( type, "harvester" ) ) {
254 				uiInfo.mapList[uiInfo.mapCount].typeBits |= ( 1 << GT_HARVESTER );
255 			}
256 #endif  // #ifdef MISSIONPACK
257 		} else {
258 			uiInfo.mapList[uiInfo.mapCount].typeBits |= ( 1 << GT_FFA );
259 		}
260 
261 		uiInfo.mapCount++;
262 		if ( uiInfo.mapCount >= MAX_MAPS ) {
263 			break;
264 		}
265 	}
266 }
267 
268 
269 /*
270 ===============
271 UI_LoadBotsFromFile
272 ===============
273 */
UI_LoadBotsFromFile(char * filename)274 static void UI_LoadBotsFromFile( char *filename ) {
275 	int len;
276 	fileHandle_t f;
277 	char buf[MAX_BOTS_TEXT];
278 
279 	len = trap_FS_FOpenFile( filename, &f, FS_READ );
280 	if ( !f ) {
281 		trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
282 		return;
283 	}
284 	if ( len >= MAX_BOTS_TEXT ) {
285 		trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_BOTS_TEXT ) );
286 		trap_FS_FCloseFile( f );
287 		return;
288 	}
289 
290 	trap_FS_Read( buf, len, f );
291 	buf[len] = 0;
292 	trap_FS_FCloseFile( f );
293 
294 	COM_Compress( buf );
295 
296 	ui_numBots += UI_ParseInfos( buf, MAX_BOTS - ui_numBots, &ui_botInfos[ui_numBots] );
297 }
298 
299 /*
300 ===============
301 UI_LoadBots
302 ===============
303 */
UI_LoadBots(void)304 void UI_LoadBots( void ) {
305 	vmCvar_t botsFile;
306 	int numdirs;
307 	char filename[128];
308 	char dirlist[1024];
309 	char*       dirptr;
310 	int i;
311 	int dirlen;
312 
313 	ui_numBots = 0;
314 
315 	trap_Cvar_Register( &botsFile, "g_botsFile", "", CVAR_INIT | CVAR_ROM );
316 	if ( *botsFile.string ) {
317 		UI_LoadBotsFromFile( botsFile.string );
318 	} else {
319 		UI_LoadBotsFromFile( "scripts/bots.txt" );
320 	}
321 
322 	// get all bots from .bot files
323 	numdirs = trap_FS_GetFileList( "scripts", ".bot", dirlist, 1024 );
324 	dirptr  = dirlist;
325 	for ( i = 0; i < numdirs; i++, dirptr += dirlen + 1 ) {
326 		dirlen = strlen( dirptr );
327 		strcpy( filename, "scripts/" );
328 		strcat( filename, dirptr );
329 		UI_LoadBotsFromFile( filename );
330 	}
331 	trap_Print( va( "%i bots parsed\n", ui_numBots ) );
332 }
333 
334 
335 /*
336 ===============
337 UI_GetBotInfoByNumber
338 ===============
339 */
UI_GetBotInfoByNumber(int num)340 char *UI_GetBotInfoByNumber( int num ) {
341 	if ( num < 0 || num >= ui_numBots ) {
342 		trap_Print( va( S_COLOR_RED "Invalid bot number: %i\n", num ) );
343 		return NULL;
344 	}
345 	return ui_botInfos[num];
346 }
347 
348 
349 /*
350 ===============
351 UI_GetBotInfoByName
352 ===============
353 */
UI_GetBotInfoByName(const char * name)354 char *UI_GetBotInfoByName( const char *name ) {
355 	int n;
356 	char    *value;
357 
358 	for ( n = 0; n < ui_numBots ; n++ ) {
359 		value = Info_ValueForKey( ui_botInfos[n], "name" );
360 		if ( !Q_stricmp( value, name ) ) {
361 			return ui_botInfos[n];
362 		}
363 	}
364 
365 	return NULL;
366 }
367 
UI_GetNumBots(void)368 int UI_GetNumBots( void ) {
369 	return ui_numBots;
370 }
371 
372 
UI_GetBotNameByNumber(int num)373 char *UI_GetBotNameByNumber( int num ) {
374 	char *info = UI_GetBotInfoByNumber( num );
375 	if ( info ) {
376 		return Info_ValueForKey( info, "name" );
377 	}
378 	return "Sarge";
379 }
380