Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

aas_file.c (21783B)


      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 Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 
     23 #include "qbsp.h"
     24 #include "../botlib/aasfile.h"
     25 #include "aas_file.h"
     26 #include "aas_store.h"
     27 #include "aas_create.h"
     28 
     29 #define AAS_Error			Error
     30 
     31 //===========================================================================
     32 //
     33 // Parameter:				-
     34 // Returns:					-
     35 // Changes Globals:		-
     36 //===========================================================================
     37 void AAS_SwapAASData(void)
     38 {
     39 	int i, j;
     40 	//bounding boxes
     41 	for (i = 0; i < aasworld.numbboxes; i++)
     42 	{
     43 		aasworld.bboxes[i].presencetype = LittleLong(aasworld.bboxes[i].presencetype);
     44 		aasworld.bboxes[i].flags = LittleLong(aasworld.bboxes[i].flags);
     45 		for (j = 0; j < 3; j++)
     46 		{
     47 			aasworld.bboxes[i].mins[j] = LittleLong(aasworld.bboxes[i].mins[j]);
     48 			aasworld.bboxes[i].maxs[j] = LittleLong(aasworld.bboxes[i].maxs[j]);
     49 		} //end for
     50 	} //end for
     51 	//vertexes
     52 	for (i = 0; i < aasworld.numvertexes; i++)
     53 	{
     54 		for (j = 0; j < 3; j++)
     55 			aasworld.vertexes[i][j] = LittleFloat(aasworld.vertexes[i][j]);
     56 	} //end for
     57 	//planes
     58 	for (i = 0; i < aasworld.numplanes; i++)
     59 	{
     60 		for (j = 0; j < 3; j++)
     61 			aasworld.planes[i].normal[j] = LittleFloat(aasworld.planes[i].normal[j]);
     62 		aasworld.planes[i].dist = LittleFloat(aasworld.planes[i].dist);
     63 		aasworld.planes[i].type = LittleLong(aasworld.planes[i].type);
     64 	} //end for
     65 	//edges
     66 	for (i = 0; i < aasworld.numedges; i++)
     67 	{
     68 		aasworld.edges[i].v[0] = LittleLong(aasworld.edges[i].v[0]);
     69 		aasworld.edges[i].v[1] = LittleLong(aasworld.edges[i].v[1]);
     70 	} //end for
     71 	//edgeindex
     72 	for (i = 0; i < aasworld.edgeindexsize; i++)
     73 	{
     74 		aasworld.edgeindex[i] = LittleLong(aasworld.edgeindex[i]);
     75 	} //end for
     76 	//faces
     77 	for (i = 0; i < aasworld.numfaces; i++)
     78 	{
     79 		aasworld.faces[i].planenum = LittleLong(aasworld.faces[i].planenum);
     80 		aasworld.faces[i].faceflags = LittleLong(aasworld.faces[i].faceflags);
     81 		aasworld.faces[i].numedges = LittleLong(aasworld.faces[i].numedges);
     82 		aasworld.faces[i].firstedge = LittleLong(aasworld.faces[i].firstedge);
     83 		aasworld.faces[i].frontarea = LittleLong(aasworld.faces[i].frontarea);
     84 		aasworld.faces[i].backarea = LittleLong(aasworld.faces[i].backarea);
     85 	} //end for
     86 	//face index
     87 	for (i = 0; i < aasworld.faceindexsize; i++)
     88 	{
     89 		aasworld.faceindex[i] = LittleLong(aasworld.faceindex[i]);
     90 	} //end for
     91 	//convex areas
     92 	for (i = 0; i < aasworld.numareas; i++)
     93 	{
     94 		aasworld.areas[i].areanum = LittleLong(aasworld.areas[i].areanum);
     95 		aasworld.areas[i].numfaces = LittleLong(aasworld.areas[i].numfaces);
     96 		aasworld.areas[i].firstface = LittleLong(aasworld.areas[i].firstface);
     97 		for (j = 0; j < 3; j++)
     98 		{
     99 			aasworld.areas[i].mins[j] = LittleFloat(aasworld.areas[i].mins[j]);
    100 			aasworld.areas[i].maxs[j] = LittleFloat(aasworld.areas[i].maxs[j]);
    101 			aasworld.areas[i].center[j] = LittleFloat(aasworld.areas[i].center[j]);
    102 		} //end for
    103 	} //end for
    104 	//area settings
    105 	for (i = 0; i < aasworld.numareasettings; i++)
    106 	{
    107 		aasworld.areasettings[i].contents = LittleLong(aasworld.areasettings[i].contents);
    108 		aasworld.areasettings[i].areaflags = LittleLong(aasworld.areasettings[i].areaflags);
    109 		aasworld.areasettings[i].presencetype = LittleLong(aasworld.areasettings[i].presencetype);
    110 		aasworld.areasettings[i].cluster = LittleLong(aasworld.areasettings[i].cluster);
    111 		aasworld.areasettings[i].clusterareanum = LittleLong(aasworld.areasettings[i].clusterareanum);
    112 		aasworld.areasettings[i].numreachableareas = LittleLong(aasworld.areasettings[i].numreachableareas);
    113 		aasworld.areasettings[i].firstreachablearea = LittleLong(aasworld.areasettings[i].firstreachablearea);
    114 	} //end for
    115 	//area reachability
    116 	for (i = 0; i < aasworld.reachabilitysize; i++)
    117 	{
    118 		aasworld.reachability[i].areanum = LittleLong(aasworld.reachability[i].areanum);
    119 		aasworld.reachability[i].facenum = LittleLong(aasworld.reachability[i].facenum);
    120 		aasworld.reachability[i].edgenum = LittleLong(aasworld.reachability[i].edgenum);
    121 		for (j = 0; j < 3; j++)
    122 		{
    123 			aasworld.reachability[i].start[j] = LittleFloat(aasworld.reachability[i].start[j]);
    124 			aasworld.reachability[i].end[j] = LittleFloat(aasworld.reachability[i].end[j]);
    125 		} //end for
    126 		aasworld.reachability[i].traveltype = LittleLong(aasworld.reachability[i].traveltype);
    127 		aasworld.reachability[i].traveltime = LittleShort(aasworld.reachability[i].traveltime);
    128 	} //end for
    129 	//nodes
    130 	for (i = 0; i < aasworld.numnodes; i++)
    131 	{
    132 		aasworld.nodes[i].planenum = LittleLong(aasworld.nodes[i].planenum);
    133 		aasworld.nodes[i].children[0] = LittleLong(aasworld.nodes[i].children[0]);
    134 		aasworld.nodes[i].children[1] = LittleLong(aasworld.nodes[i].children[1]);
    135 	} //end for
    136 	//cluster portals
    137 	for (i = 0; i < aasworld.numportals; i++)
    138 	{
    139 		aasworld.portals[i].areanum = LittleLong(aasworld.portals[i].areanum);
    140 		aasworld.portals[i].frontcluster = LittleLong(aasworld.portals[i].frontcluster);
    141 		aasworld.portals[i].backcluster = LittleLong(aasworld.portals[i].backcluster);
    142 		aasworld.portals[i].clusterareanum[0] = LittleLong(aasworld.portals[i].clusterareanum[0]);
    143 		aasworld.portals[i].clusterareanum[1] = LittleLong(aasworld.portals[i].clusterareanum[1]);
    144 	} //end for
    145 	//cluster portal index
    146 	for (i = 0; i < aasworld.portalindexsize; i++)
    147 	{
    148 		aasworld.portalindex[i] = LittleLong(aasworld.portalindex[i]);
    149 	} //end for
    150 	//cluster
    151 	for (i = 0; i < aasworld.numclusters; i++)
    152 	{
    153 		aasworld.clusters[i].numareas = LittleLong(aasworld.clusters[i].numareas);
    154 		aasworld.clusters[i].numportals = LittleLong(aasworld.clusters[i].numportals);
    155 		aasworld.clusters[i].firstportal = LittleLong(aasworld.clusters[i].firstportal);
    156 	} //end for
    157 } //end of the function AAS_SwapAASData
    158 //===========================================================================
    159 // dump the current loaded aas file
    160 //
    161 // Parameter:				-
    162 // Returns:					-
    163 // Changes Globals:		-
    164 //===========================================================================
    165 void AAS_DumpAASData(void)
    166 {
    167 	/*
    168 	if (aasworld.vertexes) FreeMemory(aasworld.vertexes);
    169 	aasworld.vertexes = NULL;
    170 	if (aasworld.planes) FreeMemory(aasworld.planes);
    171 	aasworld.planes = NULL;
    172 	if (aasworld.edges) FreeMemory(aasworld.edges);
    173 	aasworld.edges = NULL;
    174 	if (aasworld.edgeindex) FreeMemory(aasworld.edgeindex);
    175 	aasworld.edgeindex = NULL;
    176 	if (aasworld.faces) FreeMemory(aasworld.faces);
    177 	aasworld.faces = NULL;
    178 	if (aasworld.faceindex) FreeMemory(aasworld.faceindex);
    179 	aasworld.faceindex = NULL;
    180 	if (aasworld.areas) FreeMemory(aasworld.areas);
    181 	aasworld.areas = NULL;
    182 	if (aasworld.areasettings) FreeMemory(aasworld.areasettings);
    183 	aasworld.areasettings = NULL;
    184 	if (aasworld.reachability) FreeMemory(aasworld.reachability);
    185 	aasworld.reachability = NULL;
    186 	*/
    187 	aasworld.loaded = false;
    188 } //end of the function AAS_DumpAASData
    189 //===========================================================================
    190 // allocate memory and read a lump of a AAS file
    191 //
    192 // Parameter:				-
    193 // Returns:					-
    194 // Changes Globals:		-
    195 //===========================================================================
    196 char *AAS_LoadAASLump(FILE *fp, int offset, int length, void *buf)
    197 {
    198 	if (!length)
    199 	{
    200 		printf("lump size 0\n");
    201 		return buf;
    202 	} //end if
    203 	//seek to the data
    204 	if (fseek(fp, offset, SEEK_SET))
    205 	{
    206 		AAS_Error("can't seek to lump\n");
    207 		AAS_DumpAASData();
    208 		fclose(fp);
    209 		return 0;
    210 	} //end if
    211 	//allocate memory
    212 	if (!buf) buf = (void *) GetClearedMemory(length);
    213 	//read the data
    214 	if (fread((char *) buf, 1, length, fp) != length)
    215 	{
    216 		AAS_Error("can't read lump\n");
    217 		FreeMemory(buf);
    218 		AAS_DumpAASData();
    219 		fclose(fp);
    220 		return NULL;
    221 	} //end if
    222 	return buf;
    223 } //end of the function AAS_LoadAASLump
    224 //===========================================================================
    225 //
    226 // Parameter:			-
    227 // Returns:				-
    228 // Changes Globals:		-
    229 //===========================================================================
    230 void AAS_DData(unsigned char *data, int size)
    231 {
    232 	int i;
    233 
    234 	for (i = 0; i < size; i++)
    235 	{
    236 		data[i] ^= (unsigned char) i * 119;
    237 	} //end for
    238 } //end of the function AAS_DData
    239 //===========================================================================
    240 // load an aas file
    241 //
    242 // Parameter:				-
    243 // Returns:					-
    244 // Changes Globals:		-
    245 //===========================================================================
    246 qboolean AAS_LoadAASFile(char *filename, int fpoffset, int fplength)
    247 {
    248 	FILE *fp;
    249 	aas_header_t header;
    250 	int offset, length;
    251 
    252 	//dump current loaded aas file
    253 	AAS_DumpAASData();
    254 	//open the file
    255 	fp = fopen(filename, "rb");
    256 	if (!fp)
    257 	{
    258 		AAS_Error("can't open %s\n", filename);
    259 		return false;
    260 	} //end if
    261 	//seek to the correct position (in the pak file)
    262 	if (fseek(fp, fpoffset, SEEK_SET))
    263 	{
    264 		AAS_Error("can't seek to file %s\n");
    265 		fclose(fp);
    266 		return false;
    267 	} //end if
    268 	//read the header
    269 	if (fread(&header, sizeof(aas_header_t), 1, fp) != 1)
    270 	{
    271 		AAS_Error("can't read header of file %s\n", filename);
    272 		fclose(fp);
    273 		return false;
    274 	} //end if
    275 	//check header identification
    276 	header.ident = LittleLong(header.ident);
    277 	if (header.ident != AASID)
    278 	{
    279 		AAS_Error("%s is not an AAS file\n", filename);
    280 		fclose(fp);
    281 		return false;
    282 	} //end if
    283 	//check the version
    284 	header.version = LittleLong(header.version);
    285 	if (header.version != AASVERSION_OLD && header.version != AASVERSION)
    286 	{
    287 		AAS_Error("%s is version %i, not %i\n", filename, header.version, AASVERSION);
    288 		fclose(fp);
    289 		return false;
    290 	} //end if
    291 	//
    292 	if (header.version == AASVERSION)
    293 	{
    294 		AAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8);
    295 	} //end if
    296 	aasworld.bspchecksum = LittleLong(header.bspchecksum);
    297 	//load the lumps:
    298 	//bounding boxes
    299 	offset = fpoffset + LittleLong(header.lumps[AASLUMP_BBOXES].fileofs);
    300 	length = LittleLong(header.lumps[AASLUMP_BBOXES].filelen);
    301 	aasworld.bboxes = (aas_bbox_t *) AAS_LoadAASLump(fp, offset, length, aasworld.bboxes);
    302 	if (!aasworld.bboxes) return false;
    303 	aasworld.numbboxes = length / sizeof(aas_bbox_t);
    304 	//vertexes
    305 	offset = fpoffset + LittleLong(header.lumps[AASLUMP_VERTEXES].fileofs);
    306 	length = LittleLong(header.lumps[AASLUMP_VERTEXES].filelen);
    307 	aasworld.vertexes = (aas_vertex_t *) AAS_LoadAASLump(fp, offset, length, aasworld.vertexes);
    308 	if (!aasworld.vertexes) return false;
    309 	aasworld.numvertexes = length / sizeof(aas_vertex_t);
    310 	//planes
    311 	offset = fpoffset + LittleLong(header.lumps[AASLUMP_PLANES].fileofs);
    312 	length = LittleLong(header.lumps[AASLUMP_PLANES].filelen);
    313 	aasworld.planes = (aas_plane_t *) AAS_LoadAASLump(fp, offset, length, aasworld.planes);
    314 	if (!aasworld.planes) return false;
    315 	aasworld.numplanes = length / sizeof(aas_plane_t);
    316 	//edges
    317 	offset = fpoffset + LittleLong(header.lumps[AASLUMP_EDGES].fileofs);
    318 	length = LittleLong(header.lumps[AASLUMP_EDGES].filelen);
    319 	aasworld.edges = (aas_edge_t *) AAS_LoadAASLump(fp, offset, length, aasworld.edges);
    320 	if (!aasworld.edges) return false;
    321 	aasworld.numedges = length / sizeof(aas_edge_t);
    322 	//edgeindex
    323 	offset = fpoffset + LittleLong(header.lumps[AASLUMP_EDGEINDEX].fileofs);
    324 	length = LittleLong(header.lumps[AASLUMP_EDGEINDEX].filelen);
    325 	aasworld.edgeindex = (aas_edgeindex_t *) AAS_LoadAASLump(fp, offset, length, aasworld.edgeindex);
    326 	if (!aasworld.edgeindex) return false;
    327 	aasworld.edgeindexsize = length / sizeof(aas_edgeindex_t);
    328 	//faces
    329 	offset = fpoffset + LittleLong(header.lumps[AASLUMP_FACES].fileofs);
    330 	length = LittleLong(header.lumps[AASLUMP_FACES].filelen);
    331 	aasworld.faces = (aas_face_t *) AAS_LoadAASLump(fp, offset, length, aasworld.faces);
    332 	if (!aasworld.faces) return false;
    333 	aasworld.numfaces = length / sizeof(aas_face_t);
    334 	//faceindex
    335 	offset = fpoffset + LittleLong(header.lumps[AASLUMP_FACEINDEX].fileofs);
    336 	length = LittleLong(header.lumps[AASLUMP_FACEINDEX].filelen);
    337 	aasworld.faceindex = (aas_faceindex_t *) AAS_LoadAASLump(fp, offset, length, aasworld.faceindex);
    338 	if (!aasworld.faceindex) return false;
    339 	aasworld.faceindexsize = length / sizeof(int);
    340 	//convex areas
    341 	offset = fpoffset + LittleLong(header.lumps[AASLUMP_AREAS].fileofs);
    342 	length = LittleLong(header.lumps[AASLUMP_AREAS].filelen);
    343 	aasworld.areas = (aas_area_t *) AAS_LoadAASLump(fp, offset, length, aasworld.areas);
    344 	if (!aasworld.areas) return false;
    345 	aasworld.numareas = length / sizeof(aas_area_t);
    346 	//area settings
    347 	offset = fpoffset + LittleLong(header.lumps[AASLUMP_AREASETTINGS].fileofs);
    348 	length = LittleLong(header.lumps[AASLUMP_AREASETTINGS].filelen);
    349 	aasworld.areasettings = (aas_areasettings_t *) AAS_LoadAASLump(fp, offset, length, aasworld.areasettings);
    350 	if (!aasworld.areasettings) return false;
    351 	aasworld.numareasettings = length / sizeof(aas_areasettings_t);
    352 	//reachability list
    353 	offset = fpoffset + LittleLong(header.lumps[AASLUMP_REACHABILITY].fileofs);
    354 	length = LittleLong(header.lumps[AASLUMP_REACHABILITY].filelen);
    355 	aasworld.reachability = (aas_reachability_t *) AAS_LoadAASLump(fp, offset, length, aasworld.reachability);
    356 	if (length && !aasworld.reachability) return false;
    357 	aasworld.reachabilitysize = length / sizeof(aas_reachability_t);
    358 	//nodes
    359 	offset = fpoffset + LittleLong(header.lumps[AASLUMP_NODES].fileofs);
    360 	length = LittleLong(header.lumps[AASLUMP_NODES].filelen);
    361 	aasworld.nodes = (aas_node_t *) AAS_LoadAASLump(fp, offset, length, aasworld.nodes);
    362 	if (!aasworld.nodes) return false;
    363 	aasworld.numnodes = length / sizeof(aas_node_t);
    364 	//cluster portals
    365 	offset = fpoffset + LittleLong(header.lumps[AASLUMP_PORTALS].fileofs);
    366 	length = LittleLong(header.lumps[AASLUMP_PORTALS].filelen);
    367 	aasworld.portals = (aas_portal_t *) AAS_LoadAASLump(fp, offset, length, aasworld.portals);
    368 	if (length && !aasworld.portals) return false;
    369 	aasworld.numportals = length / sizeof(aas_portal_t);
    370 	//cluster portal index
    371 	offset = fpoffset + LittleLong(header.lumps[AASLUMP_PORTALINDEX].fileofs);
    372 	length = LittleLong(header.lumps[AASLUMP_PORTALINDEX].filelen);
    373 	aasworld.portalindex = (aas_portalindex_t *) AAS_LoadAASLump(fp, offset, length, aasworld.portalindex);
    374 	if (length && !aasworld.portalindex) return false;
    375 	aasworld.portalindexsize = length / sizeof(aas_portalindex_t);
    376 	//clusters
    377 	offset = fpoffset + LittleLong(header.lumps[AASLUMP_CLUSTERS].fileofs);
    378 	length = LittleLong(header.lumps[AASLUMP_CLUSTERS].filelen);
    379 	aasworld.clusters = (aas_cluster_t *) AAS_LoadAASLump(fp, offset, length, aasworld.clusters);
    380 	if (length && !aasworld.clusters) return false;
    381 	aasworld.numclusters = length / sizeof(aas_cluster_t);
    382 	//swap everything
    383 	AAS_SwapAASData();
    384 	//aas file is loaded
    385 	aasworld.loaded = true;
    386 	//close the file
    387 	fclose(fp);
    388 	return true;
    389 } //end of the function AAS_LoadAASFile
    390 //===========================================================================
    391 //
    392 // Parameter:				-
    393 // Returns:					-
    394 // Changes Globals:		-
    395 //===========================================================================
    396 int AAS_WriteAASLump(FILE *fp, aas_header_t *h, int lumpnum, void *data, int length)
    397 {
    398 	aas_lump_t *lump;
    399 
    400 	lump = &h->lumps[lumpnum];
    401 	
    402 	lump->fileofs = LittleLong(ftell(fp));
    403 	lump->filelen = LittleLong(length);
    404 
    405 	if (length > 0)
    406 	{
    407 		if (fwrite(data, length, 1, fp) < 1)
    408 		{
    409 			Log_Print("error writing lump %s\n", lumpnum);
    410 			fclose(fp);
    411 			return false;
    412 		} //end if
    413 	} //end if
    414 	return true;
    415 } //end of the function AAS_WriteAASLump
    416 //===========================================================================
    417 //
    418 // Parameter:				-
    419 // Returns:					-
    420 // Changes Globals:		-
    421 //===========================================================================
    422 void AAS_ShowNumReachabilities(int tt, char *name)
    423 {
    424 	int i, num;
    425 
    426 	num = 0;
    427 	for (i = 0; i < aasworld.reachabilitysize; i++)
    428 	{
    429 		if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == tt)
    430 			num++;
    431 	} //end for
    432 	Log_Print("%6d %s\n", num, name);
    433 } //end of the function AAS_ShowNumReachabilities
    434 //===========================================================================
    435 //
    436 // Parameter:				-
    437 // Returns:					-
    438 // Changes Globals:		-
    439 //===========================================================================
    440 void AAS_ShowTotals(void)
    441 {
    442 	Log_Print("numvertexes = %d\r\n", aasworld.numvertexes);
    443 	Log_Print("numplanes = %d\r\n", aasworld.numplanes);
    444 	Log_Print("numedges = %d\r\n", aasworld.numedges);
    445 	Log_Print("edgeindexsize = %d\r\n", aasworld.edgeindexsize);
    446 	Log_Print("numfaces = %d\r\n", aasworld.numfaces);
    447 	Log_Print("faceindexsize = %d\r\n", aasworld.faceindexsize);
    448 	Log_Print("numareas = %d\r\n", aasworld.numareas);
    449 	Log_Print("numareasettings = %d\r\n", aasworld.numareasettings);
    450 	Log_Print("reachabilitysize = %d\r\n", aasworld.reachabilitysize);
    451 	Log_Print("numnodes = %d\r\n", aasworld.numnodes);
    452 	Log_Print("numportals = %d\r\n", aasworld.numportals);
    453 	Log_Print("portalindexsize = %d\r\n", aasworld.portalindexsize);
    454 	Log_Print("numclusters = %d\r\n", aasworld.numclusters);
    455 	AAS_ShowNumReachabilities(TRAVEL_WALK, "walk");
    456 	AAS_ShowNumReachabilities(TRAVEL_CROUCH, "crouch");
    457 	AAS_ShowNumReachabilities(TRAVEL_BARRIERJUMP, "barrier jump");
    458 	AAS_ShowNumReachabilities(TRAVEL_JUMP, "jump");
    459 	AAS_ShowNumReachabilities(TRAVEL_LADDER, "ladder");
    460 	AAS_ShowNumReachabilities(TRAVEL_WALKOFFLEDGE, "walk off ledge");
    461 	AAS_ShowNumReachabilities(TRAVEL_SWIM, "swim");
    462 	AAS_ShowNumReachabilities(TRAVEL_WATERJUMP, "water jump");
    463 	AAS_ShowNumReachabilities(TRAVEL_TELEPORT, "teleport");
    464 	AAS_ShowNumReachabilities(TRAVEL_ELEVATOR, "elevator");
    465 	AAS_ShowNumReachabilities(TRAVEL_ROCKETJUMP, "rocket jump");
    466 	AAS_ShowNumReachabilities(TRAVEL_BFGJUMP, "bfg jump");
    467 	AAS_ShowNumReachabilities(TRAVEL_GRAPPLEHOOK, "grapple hook");
    468 	AAS_ShowNumReachabilities(TRAVEL_DOUBLEJUMP, "double jump");
    469 	AAS_ShowNumReachabilities(TRAVEL_RAMPJUMP, "ramp jump");
    470 	AAS_ShowNumReachabilities(TRAVEL_STRAFEJUMP, "strafe jump");
    471 	AAS_ShowNumReachabilities(TRAVEL_JUMPPAD, "jump pad");
    472 	AAS_ShowNumReachabilities(TRAVEL_FUNCBOB, "func bob");
    473 } //end of the function AAS_ShowTotals
    474 //===========================================================================
    475 // aas data is useless after writing to file because it is byte swapped
    476 //
    477 // Parameter:				-
    478 // Returns:					-
    479 // Changes Globals:		-
    480 //===========================================================================
    481 qboolean AAS_WriteAASFile(char *filename)
    482 {
    483 	aas_header_t header;
    484 	FILE *fp;
    485 
    486 	Log_Print("writing %s\n", filename);
    487 	AAS_ShowTotals();
    488 	//swap the aas data
    489 	AAS_SwapAASData();
    490 	//initialize the file header
    491 	memset(&header, 0, sizeof(aas_header_t));
    492 	header.ident = LittleLong(AASID);
    493 	header.version = LittleLong(AASVERSION);
    494 	header.bspchecksum = LittleLong(aasworld.bspchecksum);
    495 	//open a new file
    496 	fp = fopen(filename, "wb");
    497 	if (!fp)
    498 	{
    499 		Log_Print("error opening %s\n", filename);
    500 		return false;
    501 	} //end if
    502 	//write the header
    503 	if (fwrite(&header, sizeof(aas_header_t), 1, fp) < 1)
    504 	{
    505 		fclose(fp);
    506 		return false;
    507 	} //end if
    508 	//add the data lumps to the file
    509 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_BBOXES, aasworld.bboxes,
    510 		aasworld.numbboxes * sizeof(aas_bbox_t))) return false;
    511 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_VERTEXES, aasworld.vertexes,
    512 		aasworld.numvertexes * sizeof(aas_vertex_t))) return false;
    513 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_PLANES, aasworld.planes,
    514 		aasworld.numplanes * sizeof(aas_plane_t))) return false;
    515 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGES, aasworld.edges,
    516 		aasworld.numedges * sizeof(aas_edge_t))) return false;
    517 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGEINDEX, aasworld.edgeindex,
    518 		aasworld.edgeindexsize * sizeof(aas_edgeindex_t))) return false;
    519 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_FACES, aasworld.faces,
    520 		aasworld.numfaces * sizeof(aas_face_t))) return false;
    521 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_FACEINDEX, aasworld.faceindex,
    522 		aasworld.faceindexsize * sizeof(aas_faceindex_t))) return false;
    523 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_AREAS, aasworld.areas,
    524 		aasworld.numareas * sizeof(aas_area_t))) return false;
    525 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_AREASETTINGS, aasworld.areasettings,
    526 		aasworld.numareasettings * sizeof(aas_areasettings_t))) return false;
    527 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_REACHABILITY, aasworld.reachability,
    528 		aasworld.reachabilitysize * sizeof(aas_reachability_t))) return false;
    529 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_NODES, aasworld.nodes,
    530 		aasworld.numnodes * sizeof(aas_node_t))) return false;
    531 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALS, aasworld.portals,
    532 		aasworld.numportals * sizeof(aas_portal_t))) return false;
    533 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALINDEX, aasworld.portalindex,
    534 		aasworld.portalindexsize * sizeof(aas_portalindex_t))) return false;
    535 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_CLUSTERS, aasworld.clusters,
    536 		aasworld.numclusters * sizeof(aas_cluster_t))) return false;
    537 	//rewrite the header with the added lumps
    538 	fseek(fp, 0, SEEK_SET);
    539 	AAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8);
    540 	if (fwrite(&header, sizeof(aas_header_t), 1, fp) < 1)
    541 	{
    542 		fclose(fp);
    543 		return false;
    544 	} //end if
    545 	//close the file
    546 	fclose(fp);
    547 	return true;
    548 } //end of the function AAS_WriteAASFile
    549