Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

be_aas_file.c (24506B)


      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 /*****************************************************************************
     24  * name:		be_aas_file.c
     25  *
     26  * desc:		AAS file loading/writing
     27  *
     28  * $Archive: /MissionPack/code/botlib/be_aas_file.c $
     29  *
     30  *****************************************************************************/
     31 
     32 #include "../game/q_shared.h"
     33 #include "l_memory.h"
     34 #include "l_script.h"
     35 #include "l_precomp.h"
     36 #include "l_struct.h"
     37 #include "l_libvar.h"
     38 #include "l_utils.h"
     39 #include "aasfile.h"
     40 #include "../game/botlib.h"
     41 #include "../game/be_aas.h"
     42 #include "be_aas_funcs.h"
     43 #include "be_interface.h"
     44 #include "be_aas_def.h"
     45 
     46 //#define AASFILEDEBUG
     47 
     48 //===========================================================================
     49 //
     50 // Parameter:				-
     51 // Returns:					-
     52 // Changes Globals:		-
     53 //===========================================================================
     54 void AAS_SwapAASData(void)
     55 {
     56 	int i, j;
     57 	//bounding boxes
     58 	for (i = 0; i < aasworld.numbboxes; i++)
     59 	{
     60 		aasworld.bboxes[i].presencetype = LittleLong(aasworld.bboxes[i].presencetype);
     61 		aasworld.bboxes[i].flags = LittleLong(aasworld.bboxes[i].flags);
     62 		for (j = 0; j < 3; j++)
     63 		{
     64 			aasworld.bboxes[i].mins[j] = LittleLong(aasworld.bboxes[i].mins[j]);
     65 			aasworld.bboxes[i].maxs[j] = LittleLong(aasworld.bboxes[i].maxs[j]);
     66 		} //end for
     67 	} //end for
     68 	//vertexes
     69 	for (i = 0; i < aasworld.numvertexes; i++)
     70 	{
     71 		for (j = 0; j < 3; j++)
     72 			aasworld.vertexes[i][j] = LittleFloat(aasworld.vertexes[i][j]);
     73 	} //end for
     74 	//planes
     75 	for (i = 0; i < aasworld.numplanes; i++)
     76 	{
     77 		for (j = 0; j < 3; j++)
     78 			aasworld.planes[i].normal[j] = LittleFloat(aasworld.planes[i].normal[j]);
     79 		aasworld.planes[i].dist = LittleFloat(aasworld.planes[i].dist);
     80 		aasworld.planes[i].type = LittleLong(aasworld.planes[i].type);
     81 	} //end for
     82 	//edges
     83 	for (i = 0; i < aasworld.numedges; i++)
     84 	{
     85 		aasworld.edges[i].v[0] = LittleLong(aasworld.edges[i].v[0]);
     86 		aasworld.edges[i].v[1] = LittleLong(aasworld.edges[i].v[1]);
     87 	} //end for
     88 	//edgeindex
     89 	for (i = 0; i < aasworld.edgeindexsize; i++)
     90 	{
     91 		aasworld.edgeindex[i] = LittleLong(aasworld.edgeindex[i]);
     92 	} //end for
     93 	//faces
     94 	for (i = 0; i < aasworld.numfaces; i++)
     95 	{
     96 		aasworld.faces[i].planenum = LittleLong(aasworld.faces[i].planenum);
     97 		aasworld.faces[i].faceflags = LittleLong(aasworld.faces[i].faceflags);
     98 		aasworld.faces[i].numedges = LittleLong(aasworld.faces[i].numedges);
     99 		aasworld.faces[i].firstedge = LittleLong(aasworld.faces[i].firstedge);
    100 		aasworld.faces[i].frontarea = LittleLong(aasworld.faces[i].frontarea);
    101 		aasworld.faces[i].backarea = LittleLong(aasworld.faces[i].backarea);
    102 	} //end for
    103 	//face index
    104 	for (i = 0; i < aasworld.faceindexsize; i++)
    105 	{
    106 		aasworld.faceindex[i] = LittleLong(aasworld.faceindex[i]);
    107 	} //end for
    108 	//convex areas
    109 	for (i = 0; i < aasworld.numareas; i++)
    110 	{
    111 		aasworld.areas[i].areanum = LittleLong(aasworld.areas[i].areanum);
    112 		aasworld.areas[i].numfaces = LittleLong(aasworld.areas[i].numfaces);
    113 		aasworld.areas[i].firstface = LittleLong(aasworld.areas[i].firstface);
    114 		for (j = 0; j < 3; j++)
    115 		{
    116 			aasworld.areas[i].mins[j] = LittleFloat(aasworld.areas[i].mins[j]);
    117 			aasworld.areas[i].maxs[j] = LittleFloat(aasworld.areas[i].maxs[j]);
    118 			aasworld.areas[i].center[j] = LittleFloat(aasworld.areas[i].center[j]);
    119 		} //end for
    120 	} //end for
    121 	//area settings
    122 	for (i = 0; i < aasworld.numareasettings; i++)
    123 	{
    124 		aasworld.areasettings[i].contents = LittleLong(aasworld.areasettings[i].contents);
    125 		aasworld.areasettings[i].areaflags = LittleLong(aasworld.areasettings[i].areaflags);
    126 		aasworld.areasettings[i].presencetype = LittleLong(aasworld.areasettings[i].presencetype);
    127 		aasworld.areasettings[i].cluster = LittleLong(aasworld.areasettings[i].cluster);
    128 		aasworld.areasettings[i].clusterareanum = LittleLong(aasworld.areasettings[i].clusterareanum);
    129 		aasworld.areasettings[i].numreachableareas = LittleLong(aasworld.areasettings[i].numreachableareas);
    130 		aasworld.areasettings[i].firstreachablearea = LittleLong(aasworld.areasettings[i].firstreachablearea);
    131 	} //end for
    132 	//area reachability
    133 	for (i = 0; i < aasworld.reachabilitysize; i++)
    134 	{
    135 		aasworld.reachability[i].areanum = LittleLong(aasworld.reachability[i].areanum);
    136 		aasworld.reachability[i].facenum = LittleLong(aasworld.reachability[i].facenum);
    137 		aasworld.reachability[i].edgenum = LittleLong(aasworld.reachability[i].edgenum);
    138 		for (j = 0; j < 3; j++)
    139 		{
    140 			aasworld.reachability[i].start[j] = LittleFloat(aasworld.reachability[i].start[j]);
    141 			aasworld.reachability[i].end[j] = LittleFloat(aasworld.reachability[i].end[j]);
    142 		} //end for
    143 		aasworld.reachability[i].traveltype = LittleLong(aasworld.reachability[i].traveltype);
    144 		aasworld.reachability[i].traveltime = LittleShort(aasworld.reachability[i].traveltime);
    145 	} //end for
    146 	//nodes
    147 	for (i = 0; i < aasworld.numnodes; i++)
    148 	{
    149 		aasworld.nodes[i].planenum = LittleLong(aasworld.nodes[i].planenum);
    150 		aasworld.nodes[i].children[0] = LittleLong(aasworld.nodes[i].children[0]);
    151 		aasworld.nodes[i].children[1] = LittleLong(aasworld.nodes[i].children[1]);
    152 	} //end for
    153 	//cluster portals
    154 	for (i = 0; i < aasworld.numportals; i++)
    155 	{
    156 		aasworld.portals[i].areanum = LittleLong(aasworld.portals[i].areanum);
    157 		aasworld.portals[i].frontcluster = LittleLong(aasworld.portals[i].frontcluster);
    158 		aasworld.portals[i].backcluster = LittleLong(aasworld.portals[i].backcluster);
    159 		aasworld.portals[i].clusterareanum[0] = LittleLong(aasworld.portals[i].clusterareanum[0]);
    160 		aasworld.portals[i].clusterareanum[1] = LittleLong(aasworld.portals[i].clusterareanum[1]);
    161 	} //end for
    162 	//cluster portal index
    163 	for (i = 0; i < aasworld.portalindexsize; i++)
    164 	{
    165 		aasworld.portalindex[i] = LittleLong(aasworld.portalindex[i]);
    166 	} //end for
    167 	//cluster
    168 	for (i = 0; i < aasworld.numclusters; i++)
    169 	{
    170 		aasworld.clusters[i].numareas = LittleLong(aasworld.clusters[i].numareas);
    171 		aasworld.clusters[i].numreachabilityareas = LittleLong(aasworld.clusters[i].numreachabilityareas);
    172 		aasworld.clusters[i].numportals = LittleLong(aasworld.clusters[i].numportals);
    173 		aasworld.clusters[i].firstportal = LittleLong(aasworld.clusters[i].firstportal);
    174 	} //end for
    175 } //end of the function AAS_SwapAASData
    176 //===========================================================================
    177 // dump the current loaded aas file
    178 //
    179 // Parameter:				-
    180 // Returns:					-
    181 // Changes Globals:		-
    182 //===========================================================================
    183 void AAS_DumpAASData(void)
    184 {
    185 	aasworld.numbboxes = 0;
    186 	if (aasworld.bboxes) FreeMemory(aasworld.bboxes);
    187 	aasworld.bboxes = NULL;
    188 	aasworld.numvertexes = 0;
    189 	if (aasworld.vertexes) FreeMemory(aasworld.vertexes);
    190 	aasworld.vertexes = NULL;
    191 	aasworld.numplanes = 0;
    192 	if (aasworld.planes) FreeMemory(aasworld.planes);
    193 	aasworld.planes = NULL;
    194 	aasworld.numedges = 0;
    195 	if (aasworld.edges) FreeMemory(aasworld.edges);
    196 	aasworld.edges = NULL;
    197 	aasworld.edgeindexsize = 0;
    198 	if (aasworld.edgeindex) FreeMemory(aasworld.edgeindex);
    199 	aasworld.edgeindex = NULL;
    200 	aasworld.numfaces = 0;
    201 	if (aasworld.faces) FreeMemory(aasworld.faces);
    202 	aasworld.faces = NULL;
    203 	aasworld.faceindexsize = 0;
    204 	if (aasworld.faceindex) FreeMemory(aasworld.faceindex);
    205 	aasworld.faceindex = NULL;
    206 	aasworld.numareas = 0;
    207 	if (aasworld.areas) FreeMemory(aasworld.areas);
    208 	aasworld.areas = NULL;
    209 	aasworld.numareasettings = 0;
    210 	if (aasworld.areasettings) FreeMemory(aasworld.areasettings);
    211 	aasworld.areasettings = NULL;
    212 	aasworld.reachabilitysize = 0;
    213 	if (aasworld.reachability) FreeMemory(aasworld.reachability);
    214 	aasworld.reachability = NULL;
    215 	aasworld.numnodes = 0;
    216 	if (aasworld.nodes) FreeMemory(aasworld.nodes);
    217 	aasworld.nodes = NULL;
    218 	aasworld.numportals = 0;
    219 	if (aasworld.portals) FreeMemory(aasworld.portals);
    220 	aasworld.portals = NULL;
    221 	aasworld.numportals = 0;
    222 	if (aasworld.portalindex) FreeMemory(aasworld.portalindex);
    223 	aasworld.portalindex = NULL;
    224 	aasworld.portalindexsize = 0;
    225 	if (aasworld.clusters) FreeMemory(aasworld.clusters);
    226 	aasworld.clusters = NULL;
    227 	aasworld.numclusters = 0;
    228 	//
    229 	aasworld.loaded = qfalse;
    230 	aasworld.initialized = qfalse;
    231 	aasworld.savefile = qfalse;
    232 } //end of the function AAS_DumpAASData
    233 //===========================================================================
    234 //
    235 // Parameter:				-
    236 // Returns:					-
    237 // Changes Globals:		-
    238 //===========================================================================
    239 #ifdef AASFILEDEBUG
    240 void AAS_FileInfo(void)
    241 {
    242 	int i, n, optimized;
    243 
    244 	botimport.Print(PRT_MESSAGE, "version = %d\n", AASVERSION);
    245 	botimport.Print(PRT_MESSAGE, "numvertexes = %d\n", aasworld.numvertexes);
    246 	botimport.Print(PRT_MESSAGE, "numplanes = %d\n", aasworld.numplanes);
    247 	botimport.Print(PRT_MESSAGE, "numedges = %d\n", aasworld.numedges);
    248 	botimport.Print(PRT_MESSAGE, "edgeindexsize = %d\n", aasworld.edgeindexsize);
    249 	botimport.Print(PRT_MESSAGE, "numfaces = %d\n", aasworld.numfaces);
    250 	botimport.Print(PRT_MESSAGE, "faceindexsize = %d\n", aasworld.faceindexsize);
    251 	botimport.Print(PRT_MESSAGE, "numareas = %d\n", aasworld.numareas);
    252 	botimport.Print(PRT_MESSAGE, "numareasettings = %d\n", aasworld.numareasettings);
    253 	botimport.Print(PRT_MESSAGE, "reachabilitysize = %d\n", aasworld.reachabilitysize);
    254 	botimport.Print(PRT_MESSAGE, "numnodes = %d\n", aasworld.numnodes);
    255 	botimport.Print(PRT_MESSAGE, "numportals = %d\n", aasworld.numportals);
    256 	botimport.Print(PRT_MESSAGE, "portalindexsize = %d\n", aasworld.portalindexsize);
    257 	botimport.Print(PRT_MESSAGE, "numclusters = %d\n", aasworld.numclusters);
    258 	//
    259 	for (n = 0, i = 0; i < aasworld.numareasettings; i++)
    260 	{
    261 		if (aasworld.areasettings[i].areaflags & AREA_GROUNDED) n++;
    262 	} //end for
    263 	botimport.Print(PRT_MESSAGE, "num grounded areas = %d\n", n);
    264 	//
    265 	botimport.Print(PRT_MESSAGE, "planes size %d bytes\n", aasworld.numplanes * sizeof(aas_plane_t));
    266 	botimport.Print(PRT_MESSAGE, "areas size %d bytes\n", aasworld.numareas * sizeof(aas_area_t));
    267 	botimport.Print(PRT_MESSAGE, "areasettings size %d bytes\n", aasworld.numareasettings * sizeof(aas_areasettings_t));
    268 	botimport.Print(PRT_MESSAGE, "nodes size %d bytes\n", aasworld.numnodes * sizeof(aas_node_t));
    269 	botimport.Print(PRT_MESSAGE, "reachability size %d bytes\n", aasworld.reachabilitysize * sizeof(aas_reachability_t));
    270 	botimport.Print(PRT_MESSAGE, "portals size %d bytes\n", aasworld.numportals * sizeof(aas_portal_t));
    271 	botimport.Print(PRT_MESSAGE, "clusters size %d bytes\n", aasworld.numclusters * sizeof(aas_cluster_t));
    272 
    273 	optimized = aasworld.numplanes * sizeof(aas_plane_t) +
    274 					aasworld.numareas * sizeof(aas_area_t) +
    275 					aasworld.numareasettings * sizeof(aas_areasettings_t) +
    276 					aasworld.numnodes * sizeof(aas_node_t) +
    277 					aasworld.reachabilitysize * sizeof(aas_reachability_t) +
    278 					aasworld.numportals * sizeof(aas_portal_t) +
    279 					aasworld.numclusters * sizeof(aas_cluster_t);
    280 	botimport.Print(PRT_MESSAGE, "optimzed size %d KB\n", optimized >> 10);
    281 } //end of the function AAS_FileInfo
    282 #endif //AASFILEDEBUG
    283 //===========================================================================
    284 // allocate memory and read a lump of a AAS file
    285 //
    286 // Parameter:				-
    287 // Returns:					-
    288 // Changes Globals:		-
    289 //===========================================================================
    290 char *AAS_LoadAASLump(fileHandle_t fp, int offset, int length, int *lastoffset, int size)
    291 {
    292 	char *buf;
    293 	//
    294 	if (!length)
    295 	{
    296 		//just alloc a dummy
    297 		return (char *) GetClearedHunkMemory(size+1);
    298 	} //end if
    299 	//seek to the data
    300 	if (offset != *lastoffset)
    301 	{
    302 		botimport.Print(PRT_WARNING, "AAS file not sequentially read\n");
    303 		if (botimport.FS_Seek(fp, offset, FS_SEEK_SET))
    304 		{
    305 			AAS_Error("can't seek to aas lump\n");
    306 			AAS_DumpAASData();
    307 			botimport.FS_FCloseFile(fp);
    308 			return 0;
    309 		} //end if
    310 	} //end if
    311 	//allocate memory
    312 	buf = (char *) GetClearedHunkMemory(length+1);
    313 	//read the data
    314 	if (length)
    315 	{
    316 		botimport.FS_Read(buf, length, fp );
    317 		*lastoffset += length;
    318 	} //end if
    319 	return buf;
    320 } //end of the function AAS_LoadAASLump
    321 //===========================================================================
    322 //
    323 // Parameter:			-
    324 // Returns:				-
    325 // Changes Globals:		-
    326 //===========================================================================
    327 void AAS_DData(unsigned char *data, int size)
    328 {
    329 	int i;
    330 
    331 	for (i = 0; i < size; i++)
    332 	{
    333 		data[i] ^= (unsigned char) i * 119;
    334 	} //end for
    335 } //end of the function AAS_DData
    336 //===========================================================================
    337 // load an aas file
    338 //
    339 // Parameter:			-
    340 // Returns:				-
    341 // Changes Globals:		-
    342 //===========================================================================
    343 int AAS_LoadAASFile(char *filename)
    344 {
    345 	fileHandle_t fp;
    346 	aas_header_t header;
    347 	int offset, length, lastoffset;
    348 
    349 	botimport.Print(PRT_MESSAGE, "trying to load %s\n", filename);
    350 	//dump current loaded aas file
    351 	AAS_DumpAASData();
    352 	//open the file
    353 	botimport.FS_FOpenFile( filename, &fp, FS_READ );
    354 	if (!fp)
    355 	{
    356 		AAS_Error("can't open %s\n", filename);
    357 		return BLERR_CANNOTOPENAASFILE;
    358 	} //end if
    359 	//read the header
    360 	botimport.FS_Read(&header, sizeof(aas_header_t), fp );
    361 	lastoffset = sizeof(aas_header_t);
    362 	//check header identification
    363 	header.ident = LittleLong(header.ident);
    364 	if (header.ident != AASID)
    365 	{
    366 		AAS_Error("%s is not an AAS file\n", filename);
    367 		botimport.FS_FCloseFile(fp);
    368 		return BLERR_WRONGAASFILEID;
    369 	} //end if
    370 	//check the version
    371 	header.version = LittleLong(header.version);
    372 	//
    373 	if (header.version != AASVERSION_OLD && header.version != AASVERSION)
    374 	{
    375 		AAS_Error("aas file %s is version %i, not %i\n", filename, header.version, AASVERSION);
    376 		botimport.FS_FCloseFile(fp);
    377 		return BLERR_WRONGAASFILEVERSION;
    378 	} //end if
    379 	//
    380 	if (header.version == AASVERSION)
    381 	{
    382 		AAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8);
    383 	} //end if
    384 	//
    385 	aasworld.bspchecksum = atoi(LibVarGetString( "sv_mapChecksum"));
    386 	if (LittleLong(header.bspchecksum) != aasworld.bspchecksum)
    387 	{
    388 		AAS_Error("aas file %s is out of date\n", filename);
    389 		botimport.FS_FCloseFile(fp);
    390 		return BLERR_WRONGAASFILEVERSION;
    391 	} //end if
    392 	//load the lumps:
    393 	//bounding boxes
    394 	offset = LittleLong(header.lumps[AASLUMP_BBOXES].fileofs);
    395 	length = LittleLong(header.lumps[AASLUMP_BBOXES].filelen);
    396 	aasworld.bboxes = (aas_bbox_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_bbox_t));
    397 	aasworld.numbboxes = length / sizeof(aas_bbox_t);
    398 	if (aasworld.numbboxes && !aasworld.bboxes) return BLERR_CANNOTREADAASLUMP;
    399 	//vertexes
    400 	offset = LittleLong(header.lumps[AASLUMP_VERTEXES].fileofs);
    401 	length = LittleLong(header.lumps[AASLUMP_VERTEXES].filelen);
    402 	aasworld.vertexes = (aas_vertex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_vertex_t));
    403 	aasworld.numvertexes = length / sizeof(aas_vertex_t);
    404 	if (aasworld.numvertexes && !aasworld.vertexes) return BLERR_CANNOTREADAASLUMP;
    405 	//planes
    406 	offset = LittleLong(header.lumps[AASLUMP_PLANES].fileofs);
    407 	length = LittleLong(header.lumps[AASLUMP_PLANES].filelen);
    408 	aasworld.planes = (aas_plane_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_plane_t));
    409 	aasworld.numplanes = length / sizeof(aas_plane_t);
    410 	if (aasworld.numplanes && !aasworld.planes) return BLERR_CANNOTREADAASLUMP;
    411 	//edges
    412 	offset = LittleLong(header.lumps[AASLUMP_EDGES].fileofs);
    413 	length = LittleLong(header.lumps[AASLUMP_EDGES].filelen);
    414 	aasworld.edges = (aas_edge_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_edge_t));
    415 	aasworld.numedges = length / sizeof(aas_edge_t);
    416 	if (aasworld.numedges && !aasworld.edges) return BLERR_CANNOTREADAASLUMP;
    417 	//edgeindex
    418 	offset = LittleLong(header.lumps[AASLUMP_EDGEINDEX].fileofs);
    419 	length = LittleLong(header.lumps[AASLUMP_EDGEINDEX].filelen);
    420 	aasworld.edgeindex = (aas_edgeindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_edgeindex_t));
    421 	aasworld.edgeindexsize = length / sizeof(aas_edgeindex_t);
    422 	if (aasworld.edgeindexsize && !aasworld.edgeindex) return BLERR_CANNOTREADAASLUMP;
    423 	//faces
    424 	offset = LittleLong(header.lumps[AASLUMP_FACES].fileofs);
    425 	length = LittleLong(header.lumps[AASLUMP_FACES].filelen);
    426 	aasworld.faces = (aas_face_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_face_t));
    427 	aasworld.numfaces = length / sizeof(aas_face_t);
    428 	if (aasworld.numfaces && !aasworld.faces) return BLERR_CANNOTREADAASLUMP;
    429 	//faceindex
    430 	offset = LittleLong(header.lumps[AASLUMP_FACEINDEX].fileofs);
    431 	length = LittleLong(header.lumps[AASLUMP_FACEINDEX].filelen);
    432 	aasworld.faceindex = (aas_faceindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_faceindex_t));
    433 	aasworld.faceindexsize = length / sizeof(aas_faceindex_t);
    434 	if (aasworld.faceindexsize && !aasworld.faceindex) return BLERR_CANNOTREADAASLUMP;
    435 	//convex areas
    436 	offset = LittleLong(header.lumps[AASLUMP_AREAS].fileofs);
    437 	length = LittleLong(header.lumps[AASLUMP_AREAS].filelen);
    438 	aasworld.areas = (aas_area_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_area_t));
    439 	aasworld.numareas = length / sizeof(aas_area_t);
    440 	if (aasworld.numareas && !aasworld.areas) return BLERR_CANNOTREADAASLUMP;
    441 	//area settings
    442 	offset = LittleLong(header.lumps[AASLUMP_AREASETTINGS].fileofs);
    443 	length = LittleLong(header.lumps[AASLUMP_AREASETTINGS].filelen);
    444 	aasworld.areasettings = (aas_areasettings_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_areasettings_t));
    445 	aasworld.numareasettings = length / sizeof(aas_areasettings_t);
    446 	if (aasworld.numareasettings && !aasworld.areasettings) return BLERR_CANNOTREADAASLUMP;
    447 	//reachability list
    448 	offset = LittleLong(header.lumps[AASLUMP_REACHABILITY].fileofs);
    449 	length = LittleLong(header.lumps[AASLUMP_REACHABILITY].filelen);
    450 	aasworld.reachability = (aas_reachability_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_reachability_t));
    451 	aasworld.reachabilitysize = length / sizeof(aas_reachability_t);
    452 	if (aasworld.reachabilitysize && !aasworld.reachability) return BLERR_CANNOTREADAASLUMP;
    453 	//nodes
    454 	offset = LittleLong(header.lumps[AASLUMP_NODES].fileofs);
    455 	length = LittleLong(header.lumps[AASLUMP_NODES].filelen);
    456 	aasworld.nodes = (aas_node_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_node_t));
    457 	aasworld.numnodes = length / sizeof(aas_node_t);
    458 	if (aasworld.numnodes && !aasworld.nodes) return BLERR_CANNOTREADAASLUMP;
    459 	//cluster portals
    460 	offset = LittleLong(header.lumps[AASLUMP_PORTALS].fileofs);
    461 	length = LittleLong(header.lumps[AASLUMP_PORTALS].filelen);
    462 	aasworld.portals = (aas_portal_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_portal_t));
    463 	aasworld.numportals = length / sizeof(aas_portal_t);
    464 	if (aasworld.numportals && !aasworld.portals) return BLERR_CANNOTREADAASLUMP;
    465 	//cluster portal index
    466 	offset = LittleLong(header.lumps[AASLUMP_PORTALINDEX].fileofs);
    467 	length = LittleLong(header.lumps[AASLUMP_PORTALINDEX].filelen);
    468 	aasworld.portalindex = (aas_portalindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_portalindex_t));
    469 	aasworld.portalindexsize = length / sizeof(aas_portalindex_t);
    470 	if (aasworld.portalindexsize && !aasworld.portalindex) return BLERR_CANNOTREADAASLUMP;
    471 	//clusters
    472 	offset = LittleLong(header.lumps[AASLUMP_CLUSTERS].fileofs);
    473 	length = LittleLong(header.lumps[AASLUMP_CLUSTERS].filelen);
    474 	aasworld.clusters = (aas_cluster_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_cluster_t));
    475 	aasworld.numclusters = length / sizeof(aas_cluster_t);
    476 	if (aasworld.numclusters && !aasworld.clusters) return BLERR_CANNOTREADAASLUMP;
    477 	//swap everything
    478 	AAS_SwapAASData();
    479 	//aas file is loaded
    480 	aasworld.loaded = qtrue;
    481 	//close the file
    482 	botimport.FS_FCloseFile(fp);
    483 	//
    484 #ifdef AASFILEDEBUG
    485 	AAS_FileInfo();
    486 #endif //AASFILEDEBUG
    487 	//
    488 	return BLERR_NOERROR;
    489 } //end of the function AAS_LoadAASFile
    490 //===========================================================================
    491 //
    492 // Parameter:				-
    493 // Returns:					-
    494 // Changes Globals:		-
    495 //===========================================================================
    496 static int AAS_WriteAASLump_offset;
    497 
    498 int AAS_WriteAASLump(fileHandle_t fp, aas_header_t *h, int lumpnum, void *data, int length)
    499 {
    500 	aas_lump_t *lump;
    501 
    502 	lump = &h->lumps[lumpnum];
    503 	
    504 	lump->fileofs = LittleLong(AAS_WriteAASLump_offset);	//LittleLong(ftell(fp));
    505 	lump->filelen = LittleLong(length);
    506 
    507 	if (length > 0)
    508 	{
    509 		botimport.FS_Write(data, length, fp );
    510 	} //end if
    511 
    512 	AAS_WriteAASLump_offset += length;
    513 
    514 	return qtrue;
    515 } //end of the function AAS_WriteAASLump
    516 //===========================================================================
    517 // aas data is useless after writing to file because it is byte swapped
    518 //
    519 // Parameter:				-
    520 // Returns:					-
    521 // Changes Globals:		-
    522 //===========================================================================
    523 qboolean AAS_WriteAASFile(char *filename)
    524 {
    525 	aas_header_t header;
    526 	fileHandle_t fp;
    527 
    528 	botimport.Print(PRT_MESSAGE, "writing %s\n", filename);
    529 	//swap the aas data
    530 	AAS_SwapAASData();
    531 	//initialize the file header
    532 	Com_Memset(&header, 0, sizeof(aas_header_t));
    533 	header.ident = LittleLong(AASID);
    534 	header.version = LittleLong(AASVERSION);
    535 	header.bspchecksum = LittleLong(aasworld.bspchecksum);
    536 	//open a new file
    537 	botimport.FS_FOpenFile( filename, &fp, FS_WRITE );
    538 	if (!fp)
    539 	{
    540 		botimport.Print(PRT_ERROR, "error opening %s\n", filename);
    541 		return qfalse;
    542 	} //end if
    543 	//write the header
    544 	botimport.FS_Write(&header, sizeof(aas_header_t), fp);
    545 	AAS_WriteAASLump_offset = sizeof(aas_header_t);
    546 	//add the data lumps to the file
    547 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_BBOXES, aasworld.bboxes,
    548 		aasworld.numbboxes * sizeof(aas_bbox_t))) return qfalse;
    549 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_VERTEXES, aasworld.vertexes,
    550 		aasworld.numvertexes * sizeof(aas_vertex_t))) return qfalse;
    551 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_PLANES, aasworld.planes,
    552 		aasworld.numplanes * sizeof(aas_plane_t))) return qfalse;
    553 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGES, aasworld.edges,
    554 		aasworld.numedges * sizeof(aas_edge_t))) return qfalse;
    555 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGEINDEX, aasworld.edgeindex,
    556 		aasworld.edgeindexsize * sizeof(aas_edgeindex_t))) return qfalse;
    557 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_FACES, aasworld.faces,
    558 		aasworld.numfaces * sizeof(aas_face_t))) return qfalse;
    559 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_FACEINDEX, aasworld.faceindex,
    560 		aasworld.faceindexsize * sizeof(aas_faceindex_t))) return qfalse;
    561 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_AREAS, aasworld.areas,
    562 		aasworld.numareas * sizeof(aas_area_t))) return qfalse;
    563 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_AREASETTINGS, aasworld.areasettings,
    564 		aasworld.numareasettings * sizeof(aas_areasettings_t))) return qfalse;
    565 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_REACHABILITY, aasworld.reachability,
    566 		aasworld.reachabilitysize * sizeof(aas_reachability_t))) return qfalse;
    567 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_NODES, aasworld.nodes,
    568 		aasworld.numnodes * sizeof(aas_node_t))) return qfalse;
    569 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALS, aasworld.portals,
    570 		aasworld.numportals * sizeof(aas_portal_t))) return qfalse;
    571 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALINDEX, aasworld.portalindex,
    572 		aasworld.portalindexsize * sizeof(aas_portalindex_t))) return qfalse;
    573 	if (!AAS_WriteAASLump(fp, &header, AASLUMP_CLUSTERS, aasworld.clusters,
    574 		aasworld.numclusters * sizeof(aas_cluster_t))) return qfalse;
    575 	//rewrite the header with the added lumps
    576 	botimport.FS_Seek(fp, 0, FS_SEEK_SET);
    577 	AAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8);
    578 	botimport.FS_Write(&header, sizeof(aas_header_t), fp);
    579 	//close the file
    580 	botimport.FS_FCloseFile(fp);
    581 	return qtrue;
    582 } //end of the function AAS_WriteAASFile