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