2011-02-18 14:31:32 +00:00
|
|
|
/*
|
|
|
|
===========================================================================
|
|
|
|
Copyright (C) 1999-2005 Id Software, Inc.
|
|
|
|
|
|
|
|
This file is part of Quake III Arena source code.
|
|
|
|
|
|
|
|
Quake III Arena source code is free software; you can redistribute it
|
|
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
|
|
or (at your option) any later version.
|
|
|
|
|
|
|
|
Quake III Arena source code is distributed in the hope that it will be
|
|
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Quake III Arena source code; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
===========================================================================
|
|
|
|
*/
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// gameinfo.c
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "ui_local.h"
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// arena and bot info
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
int ui_numBots;
|
|
|
|
static char *ui_botInfos[MAX_BOTS];
|
|
|
|
|
|
|
|
static int ui_numArenas;
|
|
|
|
static char *ui_arenaInfos[MAX_ARENAS];
|
|
|
|
|
|
|
|
#ifndef MISSIONPACK
|
|
|
|
static int ui_numSinglePlayerArenas;
|
|
|
|
static int ui_numSpecialSinglePlayerArenas;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
UI_ParseInfos
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
int UI_ParseInfos( char *buf, int max, char *infos[] ) {
|
|
|
|
char *token;
|
|
|
|
int count;
|
|
|
|
char key[MAX_TOKEN_CHARS];
|
|
|
|
char info[MAX_INFO_STRING];
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
while ( 1 ) {
|
|
|
|
token = COM_Parse( &buf );
|
|
|
|
if ( !token[0] ) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ( strcmp( token, "{" ) ) {
|
|
|
|
Com_Printf( "Missing { in info file\n" );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( count == max ) {
|
|
|
|
Com_Printf( "Max infos exceeded\n" );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
info[0] = '\0';
|
|
|
|
while ( 1 ) {
|
|
|
|
token = COM_ParseExt( &buf, qtrue );
|
|
|
|
if ( !token[0] ) {
|
|
|
|
Com_Printf( "Unexpected end of info file\n" );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ( !strcmp( token, "}" ) ) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Q_strncpyz( key, token, sizeof( key ) );
|
|
|
|
|
|
|
|
token = COM_ParseExt( &buf, qfalse );
|
|
|
|
if ( !token[0] ) {
|
|
|
|
strcpy( token, "<NULL>" );
|
|
|
|
}
|
|
|
|
Info_SetValueForKey( info, key, token );
|
|
|
|
}
|
|
|
|
//NOTE: extra space for arena number
|
|
|
|
infos[count] = UI_Alloc(strlen(info) + strlen("\\num\\") + strlen(va("%d", MAX_ARENAS)) + 1);
|
|
|
|
if (infos[count]) {
|
|
|
|
strcpy(infos[count], info);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
UI_LoadArenasFromFile
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
static void UI_LoadArenasFromFile( char *filename ) {
|
|
|
|
int len;
|
|
|
|
fileHandle_t f;
|
|
|
|
char buf[MAX_ARENAS_TEXT];
|
|
|
|
|
|
|
|
len = trap_FS_FOpenFile( filename, &f, FS_READ );
|
|
|
|
if ( !f ) {
|
|
|
|
trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ( len >= MAX_ARENAS_TEXT ) {
|
2011-08-10 21:49:38 +00:00
|
|
|
trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i\n", filename, len, MAX_ARENAS_TEXT ) );
|
2011-02-18 14:31:32 +00:00
|
|
|
trap_FS_FCloseFile( f );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
trap_FS_Read( buf, len, f );
|
|
|
|
buf[len] = 0;
|
|
|
|
trap_FS_FCloseFile( f );
|
|
|
|
|
|
|
|
ui_numArenas += UI_ParseInfos( buf, MAX_ARENAS - ui_numArenas, &ui_arenaInfos[ui_numArenas] );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
UI_LoadArenas
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
void UI_LoadArenas( void ) {
|
|
|
|
int numdirs;
|
|
|
|
vmCvar_t arenasFile;
|
|
|
|
char filename[128];
|
|
|
|
char dirlist[1024];
|
|
|
|
char* dirptr;
|
|
|
|
int i, n;
|
|
|
|
int dirlen;
|
|
|
|
char *type;
|
|
|
|
|
|
|
|
ui_numArenas = 0;
|
|
|
|
uiInfo.mapCount = 0;
|
|
|
|
|
|
|
|
trap_Cvar_Register( &arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM );
|
|
|
|
if( *arenasFile.string ) {
|
|
|
|
UI_LoadArenasFromFile(arenasFile.string);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
UI_LoadArenasFromFile("scripts/arenas.txt");
|
|
|
|
}
|
|
|
|
|
|
|
|
// get all arenas from .arena files
|
|
|
|
numdirs = trap_FS_GetFileList("scripts", ".arena", dirlist, 1024 );
|
|
|
|
dirptr = dirlist;
|
|
|
|
for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
|
|
|
|
dirlen = strlen(dirptr);
|
|
|
|
strcpy(filename, "scripts/");
|
|
|
|
strcat(filename, dirptr);
|
|
|
|
UI_LoadArenasFromFile(filename);
|
|
|
|
}
|
|
|
|
trap_Print( va( "%i arenas parsed\n", ui_numArenas ) );
|
|
|
|
if (UI_OutOfMemory()) {
|
2012-09-15 03:03:44 +00:00
|
|
|
trap_Print(S_COLOR_YELLOW"WARNING: not enough memory in pool to load all arenas\n");
|
2011-02-18 14:31:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for( n = 0; n < ui_numArenas; n++ ) {
|
|
|
|
// determine type
|
|
|
|
|
|
|
|
uiInfo.mapList[uiInfo.mapCount].cinematic = -1;
|
|
|
|
uiInfo.mapList[uiInfo.mapCount].mapLoadName = String_Alloc(Info_ValueForKey(ui_arenaInfos[n], "map"));
|
|
|
|
uiInfo.mapList[uiInfo.mapCount].mapName = String_Alloc(Info_ValueForKey(ui_arenaInfos[n], "longname"));
|
|
|
|
uiInfo.mapList[uiInfo.mapCount].levelShot = -1;
|
|
|
|
uiInfo.mapList[uiInfo.mapCount].imageName = String_Alloc(va("levelshots/%s", uiInfo.mapList[uiInfo.mapCount].mapLoadName));
|
|
|
|
uiInfo.mapList[uiInfo.mapCount].typeBits = 0;
|
|
|
|
|
|
|
|
type = Info_ValueForKey( ui_arenaInfos[n], "type" );
|
|
|
|
// if no type specified, it will be treated as "ffa"
|
|
|
|
if( *type ) {
|
|
|
|
if( strstr( type, "ffa" ) ) {
|
|
|
|
uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_FFA);
|
|
|
|
}
|
|
|
|
if( strstr( type, "tourney" ) ) {
|
|
|
|
uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_TOURNAMENT);
|
|
|
|
}
|
|
|
|
if( strstr( type, "ctf" ) ) {
|
|
|
|
uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_CTF);
|
|
|
|
}
|
|
|
|
if( strstr( type, "oneflag" ) ) {
|
|
|
|
uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_1FCTF);
|
|
|
|
}
|
|
|
|
if( strstr( type, "overload" ) ) {
|
|
|
|
uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_OBELISK);
|
|
|
|
}
|
|
|
|
if( strstr( type, "harvester" ) ) {
|
|
|
|
uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_HARVESTER);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_FFA);
|
|
|
|
}
|
|
|
|
|
|
|
|
uiInfo.mapCount++;
|
|
|
|
if (uiInfo.mapCount >= MAX_MAPS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
UI_LoadBotsFromFile
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
static void UI_LoadBotsFromFile( char *filename ) {
|
|
|
|
int len;
|
|
|
|
fileHandle_t f;
|
|
|
|
char buf[MAX_BOTS_TEXT];
|
|
|
|
|
|
|
|
len = trap_FS_FOpenFile( filename, &f, FS_READ );
|
|
|
|
if ( !f ) {
|
|
|
|
trap_Print( va( S_COLOR_RED "file not found: %s\n", filename ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ( len >= MAX_BOTS_TEXT ) {
|
2011-08-10 21:49:38 +00:00
|
|
|
trap_Print( va( S_COLOR_RED "file too large: %s is %i, max allowed is %i\n", filename, len, MAX_BOTS_TEXT ) );
|
2011-02-18 14:31:32 +00:00
|
|
|
trap_FS_FCloseFile( f );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
trap_FS_Read( buf, len, f );
|
|
|
|
buf[len] = 0;
|
|
|
|
trap_FS_FCloseFile( f );
|
|
|
|
|
|
|
|
COM_Compress(buf);
|
|
|
|
|
|
|
|
ui_numBots += UI_ParseInfos( buf, MAX_BOTS - ui_numBots, &ui_botInfos[ui_numBots] );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
UI_LoadBots
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
void UI_LoadBots( void ) {
|
|
|
|
vmCvar_t botsFile;
|
|
|
|
int numdirs;
|
|
|
|
char filename[128];
|
|
|
|
char dirlist[1024];
|
|
|
|
char* dirptr;
|
|
|
|
int i;
|
|
|
|
int dirlen;
|
|
|
|
|
|
|
|
ui_numBots = 0;
|
|
|
|
|
|
|
|
trap_Cvar_Register( &botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM );
|
|
|
|
if( *botsFile.string ) {
|
|
|
|
UI_LoadBotsFromFile(botsFile.string);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
UI_LoadBotsFromFile("scripts/bots.txt");
|
|
|
|
}
|
|
|
|
|
|
|
|
// get all bots from .bot files
|
|
|
|
numdirs = trap_FS_GetFileList("scripts", ".bot", dirlist, 1024 );
|
|
|
|
dirptr = dirlist;
|
|
|
|
for (i = 0; i < numdirs; i++, dirptr += dirlen+1) {
|
|
|
|
dirlen = strlen(dirptr);
|
|
|
|
strcpy(filename, "scripts/");
|
|
|
|
strcat(filename, dirptr);
|
|
|
|
UI_LoadBotsFromFile(filename);
|
|
|
|
}
|
|
|
|
trap_Print( va( "%i bots parsed\n", ui_numBots ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
UI_GetBotInfoByNumber
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
char *UI_GetBotInfoByNumber( int num ) {
|
|
|
|
if( num < 0 || num >= ui_numBots ) {
|
|
|
|
trap_Print( va( S_COLOR_RED "Invalid bot number: %i\n", num ) );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return ui_botInfos[num];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
UI_GetBotInfoByName
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
char *UI_GetBotInfoByName( const char *name ) {
|
|
|
|
int n;
|
|
|
|
char *value;
|
|
|
|
|
|
|
|
for ( n = 0; n < ui_numBots ; n++ ) {
|
|
|
|
value = Info_ValueForKey( ui_botInfos[n], "name" );
|
|
|
|
if ( !Q_stricmp( value, name ) ) {
|
|
|
|
return ui_botInfos[n];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int UI_GetNumBots( void ) {
|
|
|
|
return ui_numBots;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *UI_GetBotNameByNumber( int num ) {
|
|
|
|
char *info = UI_GetBotInfoByNumber(num);
|
|
|
|
if (info) {
|
|
|
|
return Info_ValueForKey( info, "name" );
|
|
|
|
}
|
|
|
|
return "Sarge";
|
|
|
|
}
|