Esempio n. 1
0
//===========================================================================
//
// Parameter:			-
// Returns:				-
// Changes Globals:		-
//===========================================================================
int LoadCfgFile( char *filename ) {
	source_t *source;
	token_t token;
	int settingsdefined;

	source = LoadSourceFile( filename );
	if ( !source ) {
		Log_Print( "couldn't open cfg file %s\n", filename );
		return false;
	} //end if

	settingsdefined = false;
	memset( &cfg, 0, sizeof( cfg_t ) );

	while ( PC_ReadToken( source, &token ) )
	{
		if ( !stricmp( token.string, "bbox" ) ) {
			if ( cfg.numbboxes >= AAS_MAX_BBOXES ) {
				SourceError( source, "too many bounding box volumes defined" );
			} //end if
			if ( !ReadStructure( source, &bbox_struct, (char *) &cfg.bboxes[cfg.numbboxes] ) ) {
				FreeSource( source );
				return false;
			} //end if
			cfg.allpresencetypes |= cfg.bboxes[cfg.numbboxes].presencetype;
			cfg.numbboxes++;
		} //end if
		else if ( !stricmp( token.string, "settings" ) ) {
			if ( settingsdefined ) {
				SourceWarning( source, "settings already defined\n" );
			} //end if
			settingsdefined = true;
			if ( !ReadStructure( source, &cfg_struct, (char *) &cfg ) ) {
				FreeSource( source );
				return false;
			} //end if
		} //end else if
	} //end while
	if ( VectorLength( cfg.phys_gravitydirection ) < 0.9 || VectorLength( cfg.phys_gravitydirection ) > 1.1 ) {
		SourceError( source, "invalid gravity direction specified" );
	} //end if
	if ( cfg.numbboxes <= 0 ) {
		SourceError( source, "no bounding volumes specified" );
	} //end if
	FreeSource( source );
	SetCfgLibVars();
	Log_Print( "using cfg file %s\n", filename );
	return true;
} //end of the function LoadCfgFile
int PC_ReadTokenHandle( int handle, pc_token_t *token ) {
	token_t t;
	int ret;

	ret = PC_ReadToken( (source_t *)handle, &t );

	token->type = t.type;
	token->subtype = t.subtype;
	token->intvalue = t.intvalue;
	token->floatvalue = t.floatvalue;
	Q_strncpyz( token->string, t.string, MAX_TOKENLENGTH );
	token->line = t.line;
	token->linescrossed = t.linescrossed;

	// gamecode doesn't want the quotes on the string
	if ( token->type == TT_STRING ) {
		StripDoubleQuotes( token->string );
	}

	return ret;
}
Esempio n. 3
0
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
weightconfig_t *ReadWeightConfig( char *filename ) {
	int newindent, avail = 0, n;
	token_t token;
	source_t *source;
	fuzzyseperator_t *fs;
	weightconfig_t *config = NULL;
#ifdef DEBUG
	int starttime;

	starttime = Sys_MilliSeconds();
#endif //DEBUG

	if ( !LibVarGetValue( "bot_reloadcharacters" ) ) {
		avail = -1;
		for ( n = 0; n < MAX_WEIGHT_FILES; n++ )
		{
			config = weightFileList[n];
			if ( !config ) {
				if ( avail == -1 ) {
					avail = n;
				} //end if
				continue;
			} //end if
			if ( strcmp( filename, config->filename ) == 0 ) {
				//botimport.Print( PRT_MESSAGE, "retained %s\n", filename );
				return config;
			} //end if
		} //end for

		if ( avail == -1 ) {
			botimport.Print( PRT_ERROR, "weightFileList was full trying to load %s\n", filename );
			return NULL;
		} //end if
	} //end if

	source = LoadSourceFile( filename );
	if ( !source ) {
		botimport.Print( PRT_ERROR, "counldn't load %s\n", filename );
		return NULL;
	} //end if
	  //
	config = (weightconfig_t *) GetClearedMemory( sizeof( weightconfig_t ) );
	config->numweights = 0;
	Q_strncpyz( config->filename, filename, sizeof( config->filename ) );
	//parse the item config file
	while ( PC_ReadToken( source, &token ) )
	{
		if ( !strcmp( token.string, "weight" ) ) {
			if ( config->numweights >= MAX_WEIGHTS ) {
				SourceWarning( source, "too many fuzzy weights" );
				break;
			} //end if
			if ( !PC_ExpectTokenType( source, TT_STRING, 0, &token ) ) {
				FreeWeightConfig( config );
				FreeSource( source );
				return NULL;
			} //end if
			StripDoubleQuotes( token.string );
			config->weights[config->numweights].name = (char *) GetClearedMemory( strlen( token.string ) + 1 );
			strcpy( config->weights[config->numweights].name, token.string );
			if ( !PC_ExpectAnyToken( source, &token ) ) {
				FreeWeightConfig( config );
				FreeSource( source );
				return NULL;
			} //end if
			newindent = qfalse;
			if ( !strcmp( token.string, "{" ) ) {
				newindent = qtrue;
				if ( !PC_ExpectAnyToken( source, &token ) ) {
					FreeWeightConfig( config );
					FreeSource( source );
					return NULL;
				} //end if
			} //end if
			if ( !strcmp( token.string, "switch" ) ) {
				fs = ReadFuzzySeperators_r( source );
				if ( !fs ) {
					FreeWeightConfig( config );
					FreeSource( source );
					return NULL;
				} //end if
				config->weights[config->numweights].firstseperator = fs;
			} //end if
			else if ( !strcmp( token.string, "return" ) ) {
				fs = (fuzzyseperator_t *) GetClearedMemory( sizeof( fuzzyseperator_t ) );
				fs->index = 0;
				fs->value = MAX_INVENTORYVALUE;
				fs->next = NULL;
				fs->child = NULL;
				if ( !ReadFuzzyWeight( source, fs ) ) {
					FreeMemory( fs );
					FreeWeightConfig( config );
					FreeSource( source );
					return NULL;
				} //end if
				config->weights[config->numweights].firstseperator = fs;
			} //end else if
			else
			{
				SourceError( source, "invalid name %s", token.string );
				FreeWeightConfig( config );
				FreeSource( source );
				return NULL;
			} //end else
			if ( newindent ) {
				if ( !PC_ExpectTokenString( source, "}" ) ) {
					FreeWeightConfig( config );
					FreeSource( source );
					return NULL;
				} //end if
			} //end if
			config->numweights++;
		} //end if
		else
		{
			SourceError( source, "invalid name %s", token.string );
			FreeWeightConfig( config );
			FreeSource( source );
			return NULL;
		} //end else
	} //end while
	  //free the source at the end of a pass
	FreeSource( source );
	//if the file was located in a pak file
	botimport.Print( PRT_MESSAGE, "loaded %s\n", filename );
#ifdef DEBUG
	if ( botDeveloper ) {
		botimport.Print( PRT_MESSAGE, "weights loaded in %d msec\n", Sys_MilliSeconds() - starttime );
	} //end if
#endif //DEBUG
	   //
	if ( !LibVarGetValue( "bot_reloadcharacters" ) ) {
		weightFileList[avail] = config;
	} //end if
	  //
	return config;
} //end of the function ReadWeightConfig
Esempio n. 4
0
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
weaponconfig_t *LoadWeaponConfig(char *filename)
{
	int max_weaponinfo, max_projectileinfo;
	token_t token;
	char path[MAX_PATH];
	int i, j;
	source_t *source;
	weaponconfig_t *wc;
	weaponinfo_t weaponinfo;

	max_weaponinfo = (int) LibVarValue("max_weaponinfo", "32");
	if (max_weaponinfo < 0)
	{
		botimport.Print(PRT_ERROR, "max_weaponinfo = %d\n", max_weaponinfo);
		max_weaponinfo = 32;
		LibVarSet("max_weaponinfo", "32");
	} //end if
	max_projectileinfo = (int) LibVarValue("max_projectileinfo", "32");
	if (max_projectileinfo < 0)
	{
		botimport.Print(PRT_ERROR, "max_projectileinfo = %d\n", max_projectileinfo);
		max_projectileinfo = 32;
		LibVarSet("max_projectileinfo", "32");
	} //end if
	strncpy(path, filename, MAX_PATH);
	PC_SetBaseFolder(BOTFILESBASEFOLDER);
	source = LoadSourceFile(path);
	if (!source)
	{
		botimport.Print(PRT_ERROR, "counldn't load %s\n", path);
		return NULL;
	} //end if
	//initialize weapon config
	wc = (weaponconfig_t *) GetClearedHunkMemory(sizeof(weaponconfig_t) +
										max_weaponinfo * sizeof(weaponinfo_t) +
										max_projectileinfo * sizeof(projectileinfo_t));
	wc->weaponinfo = (weaponinfo_t *) ((char *) wc + sizeof(weaponconfig_t));
	wc->projectileinfo = (projectileinfo_t *) ((char *) wc->weaponinfo +
										max_weaponinfo * sizeof(weaponinfo_t));
	wc->numweapons = max_weaponinfo;
	wc->numprojectiles = 0;
	//parse the source file
	while(PC_ReadToken(source, &token))
	{
		if (!strcmp(token.string, "weaponinfo"))
		{
			Com_Memset(&weaponinfo, 0, sizeof(weaponinfo_t));
			if (!ReadStructure(source, &weaponinfo_struct, (char *) &weaponinfo))
			{
				FreeMemory(wc);
				FreeSource(source);
				return NULL;
			} //end if
			if (weaponinfo.number < 0 || weaponinfo.number >= max_weaponinfo)
			{
				botimport.Print(PRT_ERROR, "weapon info number %d out of range in %s\n", weaponinfo.number, path);
				FreeMemory(wc);
				FreeSource(source);
				return NULL;
			} //end if
			Com_Memcpy(&wc->weaponinfo[weaponinfo.number], &weaponinfo, sizeof(weaponinfo_t));
			wc->weaponinfo[weaponinfo.number].valid = qtrue;
		} //end if
		else if (!strcmp(token.string, "projectileinfo"))
		{
			if (wc->numprojectiles >= max_projectileinfo)
			{
				botimport.Print(PRT_ERROR, "more than %d projectiles defined in %s\n", max_projectileinfo, path);
				FreeMemory(wc);
				FreeSource(source);
				return NULL;
			} //end if
			Com_Memset(&wc->projectileinfo[wc->numprojectiles], 0, sizeof(projectileinfo_t));
			if (!ReadStructure(source, &projectileinfo_struct, (char *) &wc->projectileinfo[wc->numprojectiles]))
			{
				FreeMemory(wc);
				FreeSource(source);
				return NULL;
			} //end if
			wc->numprojectiles++;
		} //end if
		else
		{
			botimport.Print(PRT_ERROR, "unknown definition %s in %s\n", token.string, path);
			FreeMemory(wc);
			FreeSource(source);
			return NULL;
		} //end else
	} //end while
	FreeSource(source);
	//fix up weapons
	for (i = 0; i < wc->numweapons; i++)
	{
		if (!wc->weaponinfo[i].valid) continue;
		if (!wc->weaponinfo[i].name[0])
		{
			botimport.Print(PRT_ERROR, "weapon %d has no name in %s\n", i, path);
			FreeMemory(wc);
			return NULL;
		} //end if
		if (!wc->weaponinfo[i].projectile[0])
		{
			botimport.Print(PRT_ERROR, "weapon %s has no projectile in %s\n", wc->weaponinfo[i].name, path);
			FreeMemory(wc);
			return NULL;
		} //end if
		//find the projectile info and copy it to the weapon info
		for (j = 0; j < wc->numprojectiles; j++)
		{
			if (!strcmp(wc->projectileinfo[j].name, wc->weaponinfo[i].projectile))
			{
				Com_Memcpy(&wc->weaponinfo[i].proj, &wc->projectileinfo[j], sizeof(projectileinfo_t));
				break;
			} //end if
		} //end for
		if (j == wc->numprojectiles)
		{
			botimport.Print(PRT_ERROR, "weapon %s uses undefined projectile in %s\n", wc->weaponinfo[i].name, path);
			FreeMemory(wc);
			return NULL;
		} //end if
	} //end for
	if (!wc->numweapons) botimport.Print(PRT_WARNING, "no weapon info loaded\n");
	botimport.Print(PRT_MESSAGE, "loaded %s\n", path);
	return wc;
} //end of the function LoadWeaponConfig
Esempio n. 5
0
/*
=================
GetFunctionNamesFromFile
=================
*/
void GetFunctionNamesFromFile (char *filename)
{
	source_t	*source;
	token_t		token, lasttoken;
	int			indent = 0, brace;
	int			isStatic = 0;
	tokenList_t	*listHead;

	// filter some files out
	if ( !Q_stricmp( filename, "bg_lib.c" ) ) {
		return;
	}

	listHead = NULL;
	source = LoadSourceFile( filename );
	if ( !source ) {
		Error( "error opening %s", filename );
		return;
	}

//	printf("loaded %s\n", filename);
//	if (!PC_ReadToken(source, &lasttoken))
//	{
//		FreeSource(source);
//		return;
//	} //end if
	while ( 1 )
	{
		if ( !PC_ReadToken( source, &token ) ) {
			break;
		}
		AddTokenToList( &listHead, &token );
		if ( token.type == TT_PUNCTUATION )
		{
			switch ( token.string[0] )
			{
			case ';':
				isStatic = 0;
				break;
			case '{':
				indent++;
				break;
			case '}':
				indent--;
				if ( indent < 0 )
					indent = 0;
				break;
			case '(':
				if ( indent <= 0 && lasttoken.type == TT_NAME )
				{
					StripTokenList( listHead );

					brace = 1;
					while ( PC_ReadToken( source, &token ) )
					{
						AddTokenToList( &listHead, &token );
						if ( token.string[0] == '(' ) {
							brace++;
						}
						else if ( token.string[0] == ')' )
						{
							brace--;
							if ( brace <= 0 )
							{
								if ( !PC_ReadToken( source, &token ) ) {
									break;
								}
								if ( token.string[0] == '{' ) {
									indent++;
									if ( !isStatic && MayScrewUp( lasttoken.string ) ) {
										AddFunctionName( lasttoken.string, filename, listHead );
									}
								}	//end if
								break;
							}	//end if
						}	//end if
					}	//end while
				}	//end if
				break;
			}	//end switch
		}	//end if
		if ( token.type == TT_NAME )
		{
			if ( token.string[0] == 's' && !strcmp( token.string, "static" ) ) {
				isStatic = 1;
			}
		}
		memcpy( &lasttoken, &token, sizeof( token_t ) );
	} //end while	
	FreeSource( source );
} //end of the function GetFunctionNamesFromFile
Esempio n. 6
0
/*
=================
GetTypeNamesFromFile

Knightmare- this gets structs / vars of a given type
=================
*/
void GetTypeNamesFromFile (char *filename, char *typeName)
{
	source_t	*source;
	token_t		token, lasttoken;
	int			indent = 0;//, brace;
	int			isStatic = 0;
	int			isExtern = 0;
	tokenList_t	*listHead;

	printf("BANANE!\n");

	listHead = NULL;
	source = LoadSourceFile( filename );
	if ( !source ) {
		Error( "error opening %s", filename );
		return;
	}

	while ( 1 )
	{
		if ( !PC_ReadToken( source, &token ) ) {
			break;
		}
		if ( token.type == TT_PUNCTUATION )
		{
			switch ( token.string[0] )
			{
			case ';':
				isStatic = 0;
				isExtern = 0;
				break;
			case '{':
				indent++;
				break;
			case '}':
				indent--;
				if ( indent < 0 )
					indent = 0;
				break;
			}
		}
		if ( token.type == TT_NAME )
		{	// type declarations for pointer table must be non-static, non-extern, and global in scope
			if ( token.string[0] == 's' && !strcmp( token.string, "static" ) ) {
				isStatic = 1;
			}
			if ( token.string[0] == 'e' && !strcmp( token.string, "extern" ) ) {
				isExtern = 1;
			}
			if ( !isStatic && !isExtern && indent == 0 && !strcmp(token.string, typeName) )
			{
				if ( PC_ReadToken( source, &token ) )
				{
					if ( token.type == TT_NAME )
					{
						if (listHead)
							listHead->next = NULL;
						listHead = NULL;
						AddTokenToList( &listHead, &token );
						AddFunctionName( token.string, filename, listHead );
					}
				}
			}
		}
		memcpy( &lasttoken, &token, sizeof( token_t ) );
	}
	FreeSource( source );
}
Esempio n. 7
0
//===========================================================================
//
// Parameter:           -
// Returns:             -
// Changes Globals:     -
//===========================================================================
bot_character_t *BotLoadCharacterFromFile( char *charfile, int skill )
{
    int             indent, index, foundcharacter;
    bot_character_t *ch;
    source_t        *source;
    token_t         token;

    foundcharacter = qfalse;
    //a bot character is parsed in two phases
    PS_SetBaseFolder( "botfiles" );
    source = LoadSourceFile( charfile );
    PS_SetBaseFolder( "" );

    if ( !source )
    {
        botimport.Print( PRT_ERROR, "counldn't load %s\n", charfile );
        return NULL;
    } //end if

    ch = ( bot_character_t * ) GetClearedMemory( sizeof( bot_character_t ) + MAX_CHARACTERISTICS * sizeof( bot_characteristic_t ) );
    strcpy( ch->filename, charfile );

    while ( PC_ReadToken( source, &token ) )
    {
        if ( !strcmp( token.string, "skill" ) )
        {
            if ( !PC_ExpectTokenType( source, TT_NUMBER, 0, &token ) )
            {
                FreeSource( source );
                BotFreeCharacterStrings( ch );
                FreeMemory( ch );
                return NULL;
            } //end if

            if ( !PC_ExpectTokenString( source, "{" ) )
            {
                FreeSource( source );
                BotFreeCharacterStrings( ch );
                FreeMemory( ch );
                return NULL;
            } //end if

            //if it's the correct skill
            if ( skill < 0 || token.intvalue == skill )
            {
                foundcharacter = qtrue;
                ch->skill = token.intvalue;

                while ( PC_ExpectAnyToken( source, &token ) )
                {
                    if ( !strcmp( token.string, "}" ) )
                    {
                        break;
                    }

                    if ( token.type != TT_NUMBER || !( token.subtype & TT_INTEGER ) )
                    {
                        SourceError( source, "expected integer index, found %s\n", token.string );
                        FreeSource( source );
                        BotFreeCharacterStrings( ch );
                        FreeMemory( ch );
                        return NULL;
                    } //end if

                    index = token.intvalue;

                    if ( index < 0 || index > MAX_CHARACTERISTICS )
                    {
                        SourceError( source, "characteristic index out of range [0, %d]\n", MAX_CHARACTERISTICS );
                        FreeSource( source );
                        BotFreeCharacterStrings( ch );
                        FreeMemory( ch );
                        return NULL;
                    } //end if

                    if ( ch->c[ index ].type )
                    {
                        SourceError( source, "characteristic %d already initialized\n", index );
                        FreeSource( source );
                        BotFreeCharacterStrings( ch );
                        FreeMemory( ch );
                        return NULL;
                    } //end if

                    if ( !PC_ExpectAnyToken( source, &token ) )
                    {
                        FreeSource( source );
                        BotFreeCharacterStrings( ch );
                        FreeMemory( ch );
                        return NULL;
                    } //end if

                    if ( token.type == TT_NUMBER )
                    {
                        if ( token.subtype & TT_FLOAT )
                        {
                            ch->c[ index ].value._float = token.floatvalue;
                            ch->c[ index ].type = CT_FLOAT;
                        } //end if
                        else
                        {
                            ch->c[ index ].value.integer = token.intvalue;
                            ch->c[ index ].type = CT_INTEGER;
                        } //end else
                    } //end if
                    else if ( token.type == TT_STRING )
                    {
                        StripDoubleQuotes( token.string );
                        ch->c[ index ].value.string = GetMemory( strlen( token.string ) + 1 );
                        strcpy( ch->c[ index ].value.string, token.string );
                        ch->c[ index ].type = CT_STRING;
                    } //end else if
                    else
                    {
                        SourceError( source, "expected integer, float or string, found %s\n", token.string );
                        FreeSource( source );
                        BotFreeCharacterStrings( ch );
                        FreeMemory( ch );
                        return NULL;
                    } //end else
                } //end if

                break;
            } //end if
            else
            {
                indent = 1;

                while ( indent )
                {
                    if ( !PC_ExpectAnyToken( source, &token ) )
                    {
                        FreeSource( source );
                        BotFreeCharacterStrings( ch );
                        FreeMemory( ch );
                        return NULL;
                    } //end if

                    if ( !strcmp( token.string, "{" ) )
                    {
                        indent++;
                    }
                    else if ( !strcmp( token.string, "}" ) )
                    {
                        indent--;
                    }
                } //end while
            } //end else
        } //end if
        else
        {
            SourceError( source, "unknown definition %s\n", token.string );
            FreeSource( source );
            BotFreeCharacterStrings( ch );
            FreeMemory( ch );
            return NULL;
        } //end else
    } //end while

    FreeSource( source );

    //
    if ( !foundcharacter )
    {
        BotFreeCharacterStrings( ch );
        FreeMemory( ch );
        return NULL;
    } //end if

    return ch;
} //end of the function BotLoadCharacterFromFile
Esempio n. 8
0
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
itemconfig_t *LoadItemConfig( char *filename ) {
	int max_iteminfo;
	token_t token;
	char path[MAX_PATH];
	source_t *source;
	itemconfig_t *ic;
	iteminfo_t *ii;

	max_iteminfo = (int) LibVarValue( "max_iteminfo", "256" );
	if ( max_iteminfo < 0 ) {
		botimport.Print( PRT_ERROR, "max_iteminfo = %d\n", max_iteminfo );
		max_iteminfo = 128;
		LibVarSet( "max_iteminfo", "128" );
	}

	strncpy( path, filename, MAX_PATH );
	source = LoadSourceFile( path );
	if ( !source ) {
		botimport.Print( PRT_ERROR, "counldn't load %s\n", path );
		return NULL;
	} //end if
	  //initialize item config
	ic = (itemconfig_t *) GetClearedHunkMemory( sizeof( itemconfig_t ) +
												max_iteminfo * sizeof( iteminfo_t ) );
	ic->iteminfo = ( iteminfo_t * )( (char *) ic + sizeof( itemconfig_t ) );
	ic->numiteminfo = 0;
	//parse the item config file
	while ( PC_ReadToken( source, &token ) )
	{
		if ( !strcmp( token.string, "iteminfo" ) ) {
			if ( ic->numiteminfo >= max_iteminfo ) {
				SourceError( source, "more than %d item info defined\n", max_iteminfo );
				FreeMemory( ic );
				FreeSource( source );
				return NULL;
			} //end if
			ii = &ic->iteminfo[ic->numiteminfo];
			memset( ii, 0, sizeof( iteminfo_t ) );
			if ( !PC_ExpectTokenType( source, TT_STRING, 0, &token ) ) {
				FreeMemory( ic );
				FreeMemory( source );
				return NULL;
			} //end if
			StripDoubleQuotes( token.string );
			strncpy( ii->classname, token.string, sizeof( ii->classname ) - 1 );
			if ( !ReadStructure( source, &iteminfo_struct, (char *) ii ) ) {
				FreeMemory( ic );
				FreeSource( source );
				return NULL;
			} //end if
			ii->number = ic->numiteminfo;
			ic->numiteminfo++;
		} //end if
		else
		{
			SourceError( source, "unknown definition %s\n", token.string );
			FreeMemory( ic );
			FreeSource( source );
			return NULL;
		} //end else
	} //end while
	FreeSource( source );
	//
	if ( !ic->numiteminfo ) {
		botimport.Print( PRT_WARNING, "no item info loaded\n" );
	}
	botimport.Print( PRT_MESSAGE, "loaded %s\n", path );
	return ic;
} //end of the function LoadItemConfig
Esempio n. 9
0
static itemconfig_t* LoadItemConfig( const char* filename ) {
	int max_iteminfo = ( int )LibVarValue( "max_iteminfo", "256" );
	if ( max_iteminfo < 0 ) {
		BotImport_Print( PRT_ERROR, "max_iteminfo = %d\n", max_iteminfo );
		max_iteminfo = 256;
		LibVarSet( "max_iteminfo", "256" );
	}

	if ( GGameType & GAME_Quake3 ) {
		PC_SetBaseFolder( BOTFILESBASEFOLDER );
	}
	char path[ MAX_QPATH ];
	String::NCpyZ( path, filename, MAX_QPATH );
	source_t* source = LoadSourceFile( path );
	if ( !source ) {
		BotImport_Print( PRT_ERROR, "counldn't load %s\n", path );
		return NULL;
	}
	//initialize item config
	itemconfig_t* ic = ( itemconfig_t* )Mem_ClearedAlloc( sizeof ( itemconfig_t ) +
		max_iteminfo * sizeof ( iteminfo_t ) );
	ic->iteminfo = ( iteminfo_t* )( ( char* )ic + sizeof ( itemconfig_t ) );
	ic->numiteminfo = 0;
	//parse the item config file
	token_t token;
	while ( PC_ReadToken( source, &token ) ) {
		if ( !String::Cmp( token.string, "iteminfo" ) ) {
			if ( ic->numiteminfo >= max_iteminfo ) {
				SourceError( source, "more than %d item info defined\n", max_iteminfo );
				Mem_Free( ic );
				FreeSource( source );
				return NULL;
			}
			iteminfo_t* ii = &ic->iteminfo[ ic->numiteminfo ];
			Com_Memset( ii, 0, sizeof ( iteminfo_t ) );
			if ( !PC_ExpectTokenType( source, TT_STRING, 0, &token ) ) {
				Mem_Free( ic );
				FreeSource( source );
				return NULL;
			}
			StripDoubleQuotes( token.string );
			String::NCpy( ii->classname, token.string, sizeof ( ii->classname ) - 1 );
			if ( !ReadStructure( source, &iteminfo_struct, ( char* )ii ) ) {
				Mem_Free( ic );
				FreeSource( source );
				return NULL;
			}
			ii->number = ic->numiteminfo;
			ic->numiteminfo++;
		} else {
			SourceError( source, "unknown definition %s\n", token.string );
			Mem_Free( ic );
			FreeSource( source );
			return NULL;
		}
	}
	FreeSource( source );

	if ( !ic->numiteminfo ) {
		BotImport_Print( PRT_WARNING, "no item info loaded\n" );
	}
	BotImport_Print( PRT_MESSAGE, "loaded %s\n", path );
	return ic;
}