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 
35 int				ui_numBots;
36 static char		*ui_botInfos[MAX_BOTS];
37 
38 static int		ui_numArenas;
39 static char		*ui_arenaInfos[MAX_ARENAS];
40 
41 #ifndef MISSIONPACK
42 static int		ui_numSinglePlayerArenas;
43 static int		ui_numSpecialSinglePlayerArenas;
44 #endif
45 
46 /*
47 ===============
48 UI_ParseInfos
49 ===============
50 */
UI_ParseInfos(char * buf,int max,char * infos[])51 int UI_ParseInfos( char *buf, int max, char *infos[] ) {
52 	char	*token;
53 	int		count;
54 	char	key[MAX_TOKEN_CHARS];
55 	char	info[MAX_INFO_STRING];
56 
57 	count = 0;
58 
59 	while ( 1 ) {
60 		token = COM_Parse( &buf );
61 		if ( !token[0] ) {
62 			break;
63 		}
64 		if ( strcmp( token, "{" ) ) {
65 			Com_Printf( "Missing { in info file\n" );
66 			break;
67 		}
68 
69 		if ( count == max ) {
70 			Com_Printf( "Max infos exceeded\n" );
71 			break;
72 		}
73 
74 		info[0] = '\0';
75 		while ( 1 ) {
76 			token = COM_ParseExt( &buf, qtrue );
77 			if ( !token[0] ) {
78 				Com_Printf( "Unexpected end of info file\n" );
79 				break;
80 			}
81 			if ( !strcmp( token, "}" ) ) {
82 				break;
83 			}
84 			Q_strncpyz( key, token, sizeof( key ) );
85 
86 			token = COM_ParseExt( &buf, qfalse );
87 			if ( !token[0] ) {
88 				strcpy( token, "<NULL>" );
89 			}
90 			Info_SetValueForKey( info, key, token );
91 		}
92 		//NOTE: extra space for arena number
93 		infos[count] = UI_Alloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1);
94 		if (infos[count]) {
95 			strcpy(infos[count], info);
96 			count++;
97 		}
98 	}
99 	return count;
100 }
101 
102 /*
103 ===============
104 UI_LoadArenasFromFile
105 ===============
106 */
UI_LoadArenasFromFile(char * filename)107 static void UI_LoadArenasFromFile( char *filename ) {
108 	int				len;
109 	fileHandle_t	f;
110 	char			buf[MAX_ARENAS_TEXT];
111 
112 	len = trap_FS_FOpenFile( filename, &f, FS_READ );
113 	if ( !f ) {
114 		trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
115 		return;
116 	}
117 	if ( len >= MAX_ARENAS_TEXT ) {
118 		trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_ARENAS_TEXT ) );
119 		trap_FS_FCloseFile( f );
120 		return;
121 	}
122 
123 	trap_FS_Read( buf, len, f );
124 	buf[len] = 0;
125 	trap_FS_FCloseFile( f );
126 
127 	ui_numArenas += UI_ParseInfos( buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas] );
128 }
129 
130 /*
131 ===============
132 UI_LoadArenas
133 ===============
134 */
UI_LoadArenas(void)135 void UI_LoadArenas( void ) {
136 	int			numdirs;
137 	vmCvar_t	arenasFile;
138 	char		filename[128];
139 	char		dirlist[1024];
140 	char*		dirptr;
141 	int			i, n;
142 	int			dirlen;
143 	char		*type;
144 
145 	ui_numArenas = 0;
146 	uiInfo.mapCount = 0;
147 
148 	trap_Cvar_Register( &arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM );
149 	if( *arenasFile.string ) {
150 		UI_LoadArenasFromFile(arenasFile.string);
151 	}
152 	else {
153 		UI_LoadArenasFromFile("scripts/arenas.txt");
154 	}
155 
156 	// get all arenas from .arena files
157 	numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, 1024 );
158 	dirptr  = dirlist;
159 	for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
160 		dirlen = strlen(dirptr);
161 		strcpy(filename, "scripts/");
162 		strcat(filename, dirptr);
163 		UI_LoadArenasFromFile(filename);
164 	}
165 	trap_Print( va( "%i arenas parsed\n", ui_numArenas ) );
166 	if (UI_OutOfMemory()) {
167 		trap_Print(S_COLOR_YELLOW"WARNING: not anough memory in pool to load all arenas\n");
168 	}
169 
170 	for( n = 0; n < ui_numArenas; n++ ) {
171 		// determine type
172 
173 		uiInfo.mapList[uiInfo.mapCount].cinematic = -1;
174 		uiInfo.mapList[uiInfo.mapCount].mapLoadName = String_Alloc(Info_ValueForKey(ui_arenaInfos[n], "map"));
175 		uiInfo.mapList[uiInfo.mapCount].mapName = String_Alloc(Info_ValueForKey(ui_arenaInfos[n], "longname"));
176 		uiInfo.mapList[uiInfo.mapCount].levelShot = -1;
177 		uiInfo.mapList[uiInfo.mapCount].imageName = String_Alloc(va("levelshots/%s", uiInfo.mapList[uiInfo.mapCount].mapLoadName));
178 		uiInfo.mapList[uiInfo.mapCount].typeBits = 0;
179 
180 		type = Info_ValueForKey( ui_arenaInfos[n], "type" );
181 		// if no type specified, it will be treated as "ffa"
182 		if( *type ) {
183 			if( strstr( type, "ffa" ) ) {
184 				uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_FFA);
185 			}
186 			if( strstr( type, "tourney" ) ) {
187 				uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_TOURNAMENT);
188 			}
189 			if( strstr( type, "ctf" ) ) {
190 				uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_CTF);
191 			}
192 			if( strstr( type, "oneflag" ) ) {
193 				uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_1FCTF);
194 			}
195 			if( strstr( type, "overload" ) ) {
196 				uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_OBELISK);
197 			}
198 			if( strstr( type, "harvester" ) ) {
199 				uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_HARVESTER);
200 			}
201 		} else {
202 			uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_FFA);
203 		}
204 
205 		uiInfo.mapCount++;
206 		if (uiInfo.mapCount >= MAX_MAPS) {
207 			break;
208 		}
209 	}
210 }
211 
212 
213 /*
214 ===============
215 UI_LoadBotsFromFile
216 ===============
217 */
UI_LoadBotsFromFile(char * filename)218 static void UI_LoadBotsFromFile( char *filename ) {
219 	int				len;
220 	fileHandle_t	f;
221 	char			buf[MAX_BOTS_TEXT];
222 
223 	len = trap_FS_FOpenFile( filename, &f, FS_READ );
224 	if ( !f ) {
225 		trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
226 		return;
227 	}
228 	if ( len >= MAX_BOTS_TEXT ) {
229 		trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i", filename, len, MAX_BOTS_TEXT ) );
230 		trap_FS_FCloseFile( f );
231 		return;
232 	}
233 
234 	trap_FS_Read( buf, len, f );
235 	buf[len] = 0;
236 	trap_FS_FCloseFile( f );
237 
238 	COM_Compress(buf);
239 
240 	ui_numBots += UI_ParseInfos( buf, MAX_BOTS - ui_numBots, &ui_botInfos[ui_numBots] );
241 }
242 
243 /*
244 ===============
245 UI_LoadBots
246 ===============
247 */
UI_LoadBots(void)248 void UI_LoadBots( void ) {
249 	vmCvar_t	botsFile;
250 	int			numdirs;
251 	char		filename[128];
252 	char		dirlist[1024];
253 	char*		dirptr;
254 	int			i;
255 	int			dirlen;
256 
257 	ui_numBots = 0;
258 
259 	trap_Cvar_Register( &botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM );
260 	if( *botsFile.string ) {
261 		UI_LoadBotsFromFile(botsFile.string);
262 	}
263 	else {
264 		UI_LoadBotsFromFile("scripts/bots.txt");
265 	}
266 
267 	// get all bots from .bot files
268 	numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, 1024 );
269 	dirptr  = dirlist;
270 	for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
271 		dirlen = strlen(dirptr);
272 		strcpy(filename, "scripts/");
273 		strcat(filename, dirptr);
274 		UI_LoadBotsFromFile(filename);
275 	}
276 	trap_Print( va( "%i bots parsed\n", ui_numBots ) );
277 }
278 
279 
280 /*
281 ===============
282 UI_GetBotInfoByNumber
283 ===============
284 */
UI_GetBotInfoByNumber(int num)285 char *UI_GetBotInfoByNumber( int num ) {
286 	if( num < 0 || num >= ui_numBots ) {
287 		trap_Print( va( S_COLOR_RED "Invalid bot number: %i\n", num ) );
288 		return NULL;
289 	}
290 	return ui_botInfos[num];
291 }
292 
293 
294 /*
295 ===============
296 UI_GetBotInfoByName
297 ===============
298 */
UI_GetBotInfoByName(const char * name)299 char *UI_GetBotInfoByName( const char *name ) {
300 	int		n;
301 	char	*value;
302 
303 	for ( n = 0; n < ui_numBots ; n++ ) {
304 		value = Info_ValueForKey( ui_botInfos[n], "name" );
305 		if ( !Q_stricmp( value, name ) ) {
306 			return ui_botInfos[n];
307 		}
308 	}
309 
310 	return NULL;
311 }
312 
UI_GetNumBots(void)313 int UI_GetNumBots( void ) {
314 	return ui_numBots;
315 }
316 
317 
UI_GetBotNameByNumber(int num)318 char *UI_GetBotNameByNumber( int num ) {
319 	char *info = UI_GetBotInfoByNumber(num);
320 	if (info) {
321 		return Info_ValueForKey( info, "name" );
322 	}
323 	return "Sarge";
324 }
325