/*
===========================================================================

Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company. 

This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (RTCW MP Source Code).  

RTCW MP 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 3 of the License, or
(at your option) any later version.

RTCW MP 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 RTCW MP Source Code.  If not, see <http://www.gnu.org/licenses/>.

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.

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.

===========================================================================
*/

//===========================================================================
//
// Name:				aas_file.c
// Function:		AAS file loading and writing
// Programmer:		Mr Elusive (MrElusive@demigod.demon.nl)
// Last update:	1997-12-04
// Tab Size:		3
//===========================================================================

#include "qbsp.h"
#include "..\botlib\aasfile.h"
#include "aas_file.h"
#include "aas_store.h"
#include "aas_create.h"

#define AAS_Error           Error

//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void AAS_SwapAASData( void ) {
	int i, j;
	//bounding boxes
	for ( i = 0; i < ( *aasworld ).numbboxes; i++ )
	{
		( *aasworld ).bboxes[i].presencetype = LittleLong( ( *aasworld ).bboxes[i].presencetype );
		( *aasworld ).bboxes[i].flags = LittleLong( ( *aasworld ).bboxes[i].flags );
		for ( j = 0; j < 3; j++ )
		{
			( *aasworld ).bboxes[i].mins[j] = LittleLong( ( *aasworld ).bboxes[i].mins[j] );
			( *aasworld ).bboxes[i].maxs[j] = LittleLong( ( *aasworld ).bboxes[i].maxs[j] );
		} //end for
	} //end for
	  //vertexes
	for ( i = 0; i < ( *aasworld ).numvertexes; i++ )
	{
		for ( j = 0; j < 3; j++ )
			( *aasworld ).vertexes[i][j] = LittleFloat( ( *aasworld ).vertexes[i][j] );
	} //end for
	  //planes
	for ( i = 0; i < ( *aasworld ).numplanes; i++ )
	{
		for ( j = 0; j < 3; j++ )
			( *aasworld ).planes[i].normal[j] = LittleFloat( ( *aasworld ).planes[i].normal[j] );
		( *aasworld ).planes[i].dist = LittleFloat( ( *aasworld ).planes[i].dist );
		( *aasworld ).planes[i].type = LittleLong( ( *aasworld ).planes[i].type );
	} //end for
	  //edges
	for ( i = 0; i < ( *aasworld ).numedges; i++ )
	{
		( *aasworld ).edges[i].v[0] = LittleLong( ( *aasworld ).edges[i].v[0] );
		( *aasworld ).edges[i].v[1] = LittleLong( ( *aasworld ).edges[i].v[1] );
	} //end for
	  //edgeindex
	for ( i = 0; i < ( *aasworld ).edgeindexsize; i++ )
	{
		( *aasworld ).edgeindex[i] = LittleLong( ( *aasworld ).edgeindex[i] );
	} //end for
	  //faces
	for ( i = 0; i < ( *aasworld ).numfaces; i++ )
	{
		( *aasworld ).faces[i].planenum = LittleLong( ( *aasworld ).faces[i].planenum );
		( *aasworld ).faces[i].faceflags = LittleLong( ( *aasworld ).faces[i].faceflags );
		( *aasworld ).faces[i].numedges = LittleLong( ( *aasworld ).faces[i].numedges );
		( *aasworld ).faces[i].firstedge = LittleLong( ( *aasworld ).faces[i].firstedge );
		( *aasworld ).faces[i].frontarea = LittleLong( ( *aasworld ).faces[i].frontarea );
		( *aasworld ).faces[i].backarea = LittleLong( ( *aasworld ).faces[i].backarea );
	} //end for
	  //face index
	for ( i = 0; i < ( *aasworld ).faceindexsize; i++ )
	{
		( *aasworld ).faceindex[i] = LittleLong( ( *aasworld ).faceindex[i] );
	} //end for
	  //convex areas
	for ( i = 0; i < ( *aasworld ).numareas; i++ )
	{
		( *aasworld ).areas[i].areanum = LittleLong( ( *aasworld ).areas[i].areanum );
		( *aasworld ).areas[i].numfaces = LittleLong( ( *aasworld ).areas[i].numfaces );
		( *aasworld ).areas[i].firstface = LittleLong( ( *aasworld ).areas[i].firstface );
		for ( j = 0; j < 3; j++ )
		{
			( *aasworld ).areas[i].mins[j] = LittleFloat( ( *aasworld ).areas[i].mins[j] );
			( *aasworld ).areas[i].maxs[j] = LittleFloat( ( *aasworld ).areas[i].maxs[j] );
			( *aasworld ).areas[i].center[j] = LittleFloat( ( *aasworld ).areas[i].center[j] );
		} //end for
	} //end for
	  //area settings
	for ( i = 0; i < ( *aasworld ).numareasettings; i++ )
	{
		( *aasworld ).areasettings[i].contents = LittleLong( ( *aasworld ).areasettings[i].contents );
		( *aasworld ).areasettings[i].areaflags = LittleLong( ( *aasworld ).areasettings[i].areaflags );
		( *aasworld ).areasettings[i].presencetype = LittleLong( ( *aasworld ).areasettings[i].presencetype );
		( *aasworld ).areasettings[i].cluster = LittleLong( ( *aasworld ).areasettings[i].cluster );
		( *aasworld ).areasettings[i].clusterareanum = LittleLong( ( *aasworld ).areasettings[i].clusterareanum );
		( *aasworld ).areasettings[i].numreachableareas = LittleLong( ( *aasworld ).areasettings[i].numreachableareas );
		( *aasworld ).areasettings[i].firstreachablearea = LittleLong( ( *aasworld ).areasettings[i].firstreachablearea );
		// Ridah
		( *aasworld ).areasettings[i].groundsteepness = LittleFloat( ( *aasworld ).areasettings[i].groundsteepness );
	} //end for
	  //area reachability
	for ( i = 0; i < ( *aasworld ).reachabilitysize; i++ )
	{
		( *aasworld ).reachability[i].areanum = LittleLong( ( *aasworld ).reachability[i].areanum );
		( *aasworld ).reachability[i].facenum = LittleLong( ( *aasworld ).reachability[i].facenum );
		( *aasworld ).reachability[i].edgenum = LittleLong( ( *aasworld ).reachability[i].edgenum );
		for ( j = 0; j < 3; j++ )
		{
			( *aasworld ).reachability[i].start[j] = LittleFloat( ( *aasworld ).reachability[i].start[j] );
			( *aasworld ).reachability[i].end[j] = LittleFloat( ( *aasworld ).reachability[i].end[j] );
		} //end for
		( *aasworld ).reachability[i].traveltype = LittleLong( ( *aasworld ).reachability[i].traveltype );
		( *aasworld ).reachability[i].traveltime = LittleShort( ( *aasworld ).reachability[i].traveltime );
	} //end for
	  //nodes
	for ( i = 0; i < ( *aasworld ).numnodes; i++ )
	{
		( *aasworld ).nodes[i].planenum = LittleLong( ( *aasworld ).nodes[i].planenum );
		( *aasworld ).nodes[i].children[0] = LittleLong( ( *aasworld ).nodes[i].children[0] );
		( *aasworld ).nodes[i].children[1] = LittleLong( ( *aasworld ).nodes[i].children[1] );
	} //end for
	  //cluster portals
	for ( i = 0; i < ( *aasworld ).numportals; i++ )
	{
		( *aasworld ).portals[i].areanum = LittleLong( ( *aasworld ).portals[i].areanum );
		( *aasworld ).portals[i].frontcluster = LittleLong( ( *aasworld ).portals[i].frontcluster );
		( *aasworld ).portals[i].backcluster = LittleLong( ( *aasworld ).portals[i].backcluster );
		( *aasworld ).portals[i].clusterareanum[0] = LittleLong( ( *aasworld ).portals[i].clusterareanum[0] );
		( *aasworld ).portals[i].clusterareanum[1] = LittleLong( ( *aasworld ).portals[i].clusterareanum[1] );
	} //end for
	  //cluster portal index
	for ( i = 0; i < ( *aasworld ).portalindexsize; i++ )
	{
		( *aasworld ).portalindex[i] = LittleLong( ( *aasworld ).portalindex[i] );
	} //end for
	  //cluster
	for ( i = 0; i < ( *aasworld ).numclusters; i++ )
	{
		( *aasworld ).clusters[i].numareas = LittleLong( ( *aasworld ).clusters[i].numareas );
		( *aasworld ).clusters[i].numportals = LittleLong( ( *aasworld ).clusters[i].numportals );
		( *aasworld ).clusters[i].firstportal = LittleLong( ( *aasworld ).clusters[i].firstportal );
	} //end for
} //end of the function AAS_SwapAASData
//===========================================================================
// dump the current loaded aas file
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void AAS_DumpAASData( void ) {
	/*
	if ((*aasworld).vertexes) FreeMemory((*aasworld).vertexes);
	(*aasworld).vertexes = NULL;
	if ((*aasworld).planes) FreeMemory((*aasworld).planes);
	(*aasworld).planes = NULL;
	if ((*aasworld).edges) FreeMemory((*aasworld).edges);
	(*aasworld).edges = NULL;
	if ((*aasworld).edgeindex) FreeMemory((*aasworld).edgeindex);
	(*aasworld).edgeindex = NULL;
	if ((*aasworld).faces) FreeMemory((*aasworld).faces);
	(*aasworld).faces = NULL;
	if ((*aasworld).faceindex) FreeMemory((*aasworld).faceindex);
	(*aasworld).faceindex = NULL;
	if ((*aasworld).areas) FreeMemory((*aasworld).areas);
	(*aasworld).areas = NULL;
	if ((*aasworld).areasettings) FreeMemory((*aasworld).areasettings);
	(*aasworld).areasettings = NULL;
	if ((*aasworld).reachability) FreeMemory((*aasworld).reachability);
	(*aasworld).reachability = NULL;
	*/
	( *aasworld ).loaded = false;
} //end of the function AAS_DumpAASData
//===========================================================================
// allocate memory and read a lump of a AAS file
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
char *AAS_LoadAASLump( FILE *fp, int offset, int length, void *buf ) {
	if ( !length ) {
		printf( "lump size 0\n" );
		return buf;
	} //end if
	  //seek to the data
	if ( fseek( fp, offset, SEEK_SET ) ) {
		AAS_Error( "can't seek to lump\n" );
		AAS_DumpAASData();
		fclose( fp );
		return 0;
	} //end if
	  //allocate memory
	if ( !buf ) {
		buf = (void *) GetClearedMemory( length );
	}
	//read the data
	if ( fread( (char *) buf, 1, length, fp ) != length ) {
		AAS_Error( "can't read lump\n" );
		FreeMemory( buf );
		AAS_DumpAASData();
		fclose( fp );
		return NULL;
	} //end if
	return buf;
} //end of the function AAS_LoadAASLump
//===========================================================================
//
// Parameter:			-
// Returns:				-
// Changes Globals:		-
//===========================================================================
void AAS_DData( unsigned char *data, int size ) {
	int i;

	for ( i = 0; i < size; i++ )
	{
		data[i] ^= (unsigned char) i * 119;
	} //end for
} //end of the function AAS_DData
//===========================================================================
// load an aas file
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
qboolean AAS_LoadAASFile( char *filename, int fpoffset, int fplength ) {
	FILE *fp;
	aas_header_t header;
	int offset, length;

	//dump current loaded aas file
	AAS_DumpAASData();
	//open the file
	fp = fopen( filename, "rb" );
	if ( !fp ) {
		AAS_Error( "can't open %s\n", filename );
		return false;
	} //end if
	  //seek to the correct position (in the pak file)
	if ( fseek( fp, fpoffset, SEEK_SET ) ) {
		AAS_Error( "can't seek to file %s\n" );
		fclose( fp );
		return false;
	} //end if
	  //read the header
	if ( fread( &header, sizeof( aas_header_t ), 1, fp ) != 1 ) {
		AAS_Error( "can't read header of file %s\n", filename );
		fclose( fp );
		return false;
	} //end if
	  //check header identification
	header.ident = LittleLong( header.ident );
	if ( header.ident != AASID ) {
		AAS_Error( "%s is not an AAS file\n", filename );
		fclose( fp );
		return false;
	} //end if
	  //check the version
	header.version = LittleLong( header.version );
	if ( header.version != AASVERSION ) {
		AAS_Error( "%s is version %i, not %i\n", filename, header.version, AASVERSION );
		fclose( fp );
		return false;
	} //end if
	  //
	if ( header.version == AASVERSION ) {
		AAS_DData( (unsigned char *) &header + 8, sizeof( aas_header_t ) - 8 );
	} //end if
	( *aasworld ).bspchecksum = LittleLong( header.bspchecksum );
	//load the lumps:
	//bounding boxes
	offset = fpoffset + LittleLong( header.lumps[AASLUMP_BBOXES].fileofs );
	length = LittleLong( header.lumps[AASLUMP_BBOXES].filelen );
	( *aasworld ).bboxes = (aas_bbox_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).bboxes );
	if ( !( *aasworld ).bboxes ) {
		return false;
	}
	( *aasworld ).numbboxes = length / sizeof( aas_bbox_t );
	//vertexes
	offset = fpoffset + LittleLong( header.lumps[AASLUMP_VERTEXES].fileofs );
	length = LittleLong( header.lumps[AASLUMP_VERTEXES].filelen );
	( *aasworld ).vertexes = (aas_vertex_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).vertexes );
	if ( !( *aasworld ).vertexes ) {
		return false;
	}
	( *aasworld ).numvertexes = length / sizeof( aas_vertex_t );
	//planes
	offset = fpoffset + LittleLong( header.lumps[AASLUMP_PLANES].fileofs );
	length = LittleLong( header.lumps[AASLUMP_PLANES].filelen );
	( *aasworld ).planes = (aas_plane_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).planes );
	if ( !( *aasworld ).planes ) {
		return false;
	}
	( *aasworld ).numplanes = length / sizeof( aas_plane_t );
	//edges
	offset = fpoffset + LittleLong( header.lumps[AASLUMP_EDGES].fileofs );
	length = LittleLong( header.lumps[AASLUMP_EDGES].filelen );
	( *aasworld ).edges = (aas_edge_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).edges );
	if ( !( *aasworld ).edges ) {
		return false;
	}
	( *aasworld ).numedges = length / sizeof( aas_edge_t );
	//edgeindex
	offset = fpoffset + LittleLong( header.lumps[AASLUMP_EDGEINDEX].fileofs );
	length = LittleLong( header.lumps[AASLUMP_EDGEINDEX].filelen );
	( *aasworld ).edgeindex = (aas_edgeindex_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).edgeindex );
	if ( !( *aasworld ).edgeindex ) {
		return false;
	}
	( *aasworld ).edgeindexsize = length / sizeof( aas_edgeindex_t );
	//faces
	offset = fpoffset + LittleLong( header.lumps[AASLUMP_FACES].fileofs );
	length = LittleLong( header.lumps[AASLUMP_FACES].filelen );
	( *aasworld ).faces = (aas_face_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).faces );
	if ( !( *aasworld ).faces ) {
		return false;
	}
	( *aasworld ).numfaces = length / sizeof( aas_face_t );
	//faceindex
	offset = fpoffset + LittleLong( header.lumps[AASLUMP_FACEINDEX].fileofs );
	length = LittleLong( header.lumps[AASLUMP_FACEINDEX].filelen );
	( *aasworld ).faceindex = (aas_faceindex_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).faceindex );
	if ( !( *aasworld ).faceindex ) {
		return false;
	}
	( *aasworld ).faceindexsize = length / sizeof( int );
	//convex areas
	offset = fpoffset + LittleLong( header.lumps[AASLUMP_AREAS].fileofs );
	length = LittleLong( header.lumps[AASLUMP_AREAS].filelen );
	( *aasworld ).areas = (aas_area_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).areas );
	if ( !( *aasworld ).areas ) {
		return false;
	}
	( *aasworld ).numareas = length / sizeof( aas_area_t );
	//area settings
	offset = fpoffset + LittleLong( header.lumps[AASLUMP_AREASETTINGS].fileofs );
	length = LittleLong( header.lumps[AASLUMP_AREASETTINGS].filelen );
	( *aasworld ).areasettings = (aas_areasettings_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).areasettings );
	if ( !( *aasworld ).areasettings ) {
		return false;
	}
	( *aasworld ).numareasettings = length / sizeof( aas_areasettings_t );
	//reachability list
	offset = fpoffset + LittleLong( header.lumps[AASLUMP_REACHABILITY].fileofs );
	length = LittleLong( header.lumps[AASLUMP_REACHABILITY].filelen );
	( *aasworld ).reachability = (aas_reachability_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).reachability );
	if ( length && !( *aasworld ).reachability ) {
		return false;
	}
	( *aasworld ).reachabilitysize = length / sizeof( aas_reachability_t );
	//nodes
	offset = fpoffset + LittleLong( header.lumps[AASLUMP_NODES].fileofs );
	length = LittleLong( header.lumps[AASLUMP_NODES].filelen );
	( *aasworld ).nodes = (aas_node_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).nodes );
	if ( !( *aasworld ).nodes ) {
		return false;
	}
	( *aasworld ).numnodes = length / sizeof( aas_node_t );
	//cluster portals
	offset = fpoffset + LittleLong( header.lumps[AASLUMP_PORTALS].fileofs );
	length = LittleLong( header.lumps[AASLUMP_PORTALS].filelen );
	( *aasworld ).portals = (aas_portal_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).portals );
	if ( length && !( *aasworld ).portals ) {
		return false;
	}
	( *aasworld ).numportals = length / sizeof( aas_portal_t );
	//cluster portal index
	offset = fpoffset + LittleLong( header.lumps[AASLUMP_PORTALINDEX].fileofs );
	length = LittleLong( header.lumps[AASLUMP_PORTALINDEX].filelen );
	( *aasworld ).portalindex = (aas_portalindex_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).portalindex );
	if ( length && !( *aasworld ).portalindex ) {
		return false;
	}
	( *aasworld ).portalindexsize = length / sizeof( aas_portalindex_t );
	//clusters
	offset = fpoffset + LittleLong( header.lumps[AASLUMP_CLUSTERS].fileofs );
	length = LittleLong( header.lumps[AASLUMP_CLUSTERS].filelen );
	( *aasworld ).clusters = (aas_cluster_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).clusters );
	if ( length && !( *aasworld ).clusters ) {
		return false;
	}
	( *aasworld ).numclusters = length / sizeof( aas_cluster_t );
	//swap everything
	AAS_SwapAASData();
	//aas file is loaded
	( *aasworld ).loaded = true;
	//close the file
	fclose( fp );
	return true;
} //end of the function AAS_LoadAASFile
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
int AAS_WriteAASLump( FILE *fp, aas_header_t *h, int lumpnum, void *data, int length ) {
	aas_lump_t *lump;

	lump = &h->lumps[lumpnum];

	lump->fileofs = LittleLong( ftell( fp ) );
	lump->filelen = LittleLong( length );

	if ( length > 0 ) {
		if ( fwrite( data, length, 1, fp ) < 1 ) {
			Log_Print( "error writing lump %s\n", lumpnum );
			fclose( fp );
			return false;
		} //end if
	} //end if
	return true;
} //end of the function AAS_WriteAASLump
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void AAS_ShowNumReachabilities( int tt, char *name ) {
	int i, num;

	num = 0;
	for ( i = 0; i < ( *aasworld ).reachabilitysize; i++ )
	{
		if ( ( ( *aasworld ).reachability[i].traveltype & TRAVELTYPE_MASK ) == tt ) {
			num++;
		}
	} //end for
	Log_Print( "%6d %s\n", num, name );
} //end of the function AAS_ShowNumReachabilities
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void AAS_ShowTotals( void ) {
	Log_Print( "numvertexes = %d\r\n", ( *aasworld ).numvertexes );
	Log_Print( "numplanes = %d\r\n", ( *aasworld ).numplanes );
	Log_Print( "numedges = %d\r\n", ( *aasworld ).numedges );
	Log_Print( "edgeindexsize = %d\r\n", ( *aasworld ).edgeindexsize );
	Log_Print( "numfaces = %d\r\n", ( *aasworld ).numfaces );
	Log_Print( "faceindexsize = %d\r\n", ( *aasworld ).faceindexsize );
	Log_Print( "numareas = %d\r\n", ( *aasworld ).numareas );
	Log_Print( "numareasettings = %d\r\n", ( *aasworld ).numareasettings );
	Log_Print( "reachabilitysize = %d\r\n", ( *aasworld ).reachabilitysize );
	Log_Print( "numnodes = %d\r\n", ( *aasworld ).numnodes );
	Log_Print( "numportals = %d\r\n", ( *aasworld ).numportals );
	Log_Print( "portalindexsize = %d\r\n", ( *aasworld ).portalindexsize );
	Log_Print( "numclusters = %d\r\n", ( *aasworld ).numclusters );
	AAS_ShowNumReachabilities( TRAVEL_WALK, "walk" );
	AAS_ShowNumReachabilities( TRAVEL_CROUCH, "crouch" );
	AAS_ShowNumReachabilities( TRAVEL_BARRIERJUMP, "barrier jump" );
	AAS_ShowNumReachabilities( TRAVEL_JUMP, "jump" );
	AAS_ShowNumReachabilities( TRAVEL_LADDER, "ladder" );
	AAS_ShowNumReachabilities( TRAVEL_WALKOFFLEDGE, "walk off ledge" );
	AAS_ShowNumReachabilities( TRAVEL_SWIM, "swim" );
	AAS_ShowNumReachabilities( TRAVEL_WATERJUMP, "water jump" );
	AAS_ShowNumReachabilities( TRAVEL_TELEPORT, "teleport" );
	AAS_ShowNumReachabilities( TRAVEL_ELEVATOR, "elevator" );
	AAS_ShowNumReachabilities( TRAVEL_ROCKETJUMP, "rocket jump" );
	AAS_ShowNumReachabilities( TRAVEL_BFGJUMP, "bfg jump" );
	AAS_ShowNumReachabilities( TRAVEL_GRAPPLEHOOK, "grapple hook" );
	AAS_ShowNumReachabilities( TRAVEL_DOUBLEJUMP, "double jump" );
	AAS_ShowNumReachabilities( TRAVEL_RAMPJUMP, "ramp jump" );
	AAS_ShowNumReachabilities( TRAVEL_STRAFEJUMP, "strafe jump" );
	AAS_ShowNumReachabilities( TRAVEL_JUMPPAD, "jump pad" );
	AAS_ShowNumReachabilities( TRAVEL_FUNCBOB, "func bob" );

} //end of the function AAS_ShowTotals
//===========================================================================
// aas data is useless after writing to file because it is byte swapped
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
qboolean AAS_WriteAASFile( char *filename ) {
	aas_header_t header;
	FILE *fp;

	Log_Print( "writing %s\n", filename );
	AAS_ShowTotals();
	//swap the aas data
	AAS_SwapAASData();
	//initialize the file header
	memset( &header, 0, sizeof( aas_header_t ) );
	header.ident = LittleLong( AASID );
	header.version = LittleLong( AASVERSION );
	header.bspchecksum = LittleLong( ( *aasworld ).bspchecksum );
	//open a new file
	fp = fopen( filename, "wb" );
	if ( !fp ) {
		Log_Print( "error opening %s\n", filename );
		return false;
	} //end if
	  //write the header
	if ( fwrite( &header, sizeof( aas_header_t ), 1, fp ) < 1 ) {
		fclose( fp );
		return false;
	} //end if
	  //add the data lumps to the file
	if ( !AAS_WriteAASLump( fp, &header, AASLUMP_BBOXES, ( *aasworld ).bboxes,
							( *aasworld ).numbboxes * sizeof( aas_bbox_t ) ) ) {
		return false;
	}
	if ( !AAS_WriteAASLump( fp, &header, AASLUMP_VERTEXES, ( *aasworld ).vertexes,
							( *aasworld ).numvertexes * sizeof( aas_vertex_t ) ) ) {
		return false;
	}
	if ( !AAS_WriteAASLump( fp, &header, AASLUMP_PLANES, ( *aasworld ).planes,
							( *aasworld ).numplanes * sizeof( aas_plane_t ) ) ) {
		return false;
	}
	if ( !AAS_WriteAASLump( fp, &header, AASLUMP_EDGES, ( *aasworld ).edges,
							( *aasworld ).numedges * sizeof( aas_edge_t ) ) ) {
		return false;
	}
	if ( !AAS_WriteAASLump( fp, &header, AASLUMP_EDGEINDEX, ( *aasworld ).edgeindex,
							( *aasworld ).edgeindexsize * sizeof( aas_edgeindex_t ) ) ) {
		return false;
	}
	if ( !AAS_WriteAASLump( fp, &header, AASLUMP_FACES, ( *aasworld ).faces,
							( *aasworld ).numfaces * sizeof( aas_face_t ) ) ) {
		return false;
	}
	if ( !AAS_WriteAASLump( fp, &header, AASLUMP_FACEINDEX, ( *aasworld ).faceindex,
							( *aasworld ).faceindexsize * sizeof( aas_faceindex_t ) ) ) {
		return false;
	}
	if ( !AAS_WriteAASLump( fp, &header, AASLUMP_AREAS, ( *aasworld ).areas,
							( *aasworld ).numareas * sizeof( aas_area_t ) ) ) {
		return false;
	}
	if ( !AAS_WriteAASLump( fp, &header, AASLUMP_AREASETTINGS, ( *aasworld ).areasettings,
							( *aasworld ).numareasettings * sizeof( aas_areasettings_t ) ) ) {
		return false;
	}
	if ( !AAS_WriteAASLump( fp, &header, AASLUMP_REACHABILITY, ( *aasworld ).reachability,
							( *aasworld ).reachabilitysize * sizeof( aas_reachability_t ) ) ) {
		return false;
	}
	if ( !AAS_WriteAASLump( fp, &header, AASLUMP_NODES, ( *aasworld ).nodes,
							( *aasworld ).numnodes * sizeof( aas_node_t ) ) ) {
		return false;
	}
	if ( !AAS_WriteAASLump( fp, &header, AASLUMP_PORTALS, ( *aasworld ).portals,
							( *aasworld ).numportals * sizeof( aas_portal_t ) ) ) {
		return false;
	}
	if ( !AAS_WriteAASLump( fp, &header, AASLUMP_PORTALINDEX, ( *aasworld ).portalindex,
							( *aasworld ).portalindexsize * sizeof( aas_portalindex_t ) ) ) {
		return false;
	}
	if ( !AAS_WriteAASLump( fp, &header, AASLUMP_CLUSTERS, ( *aasworld ).clusters,
							( *aasworld ).numclusters * sizeof( aas_cluster_t ) ) ) {
		return false;
	}
	//rewrite the header with the added lumps
	fseek( fp, 0, SEEK_SET );
	AAS_DData( (unsigned char *) &header + 8, sizeof( aas_header_t ) - 8 );
	if ( fwrite( &header, sizeof( aas_header_t ), 1, fp ) < 1 ) {
		fclose( fp );
		return false;
	} //end if
	  //close the file
	fclose( fp );
	return true;
} //end of the function AAS_WriteAASFile

