//=========================================================================== // 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: - //=========================================================================== int AAS_UpdatePortal(int areanum, int clusternum) { int portalnum; aas_portal_t *portal; aas_cluster_t *cluster; //find the portal of the area for (portalnum = 1; portalnum < aasworld.numportals; portalnum++) { if (aasworld.portals[portalnum].areanum == areanum) break; } //end for // if (portalnum == aasworld.numportals) { AAS_Error("no portal of area %d", areanum); return qtrue; } //end if // portal = &aasworld.portals[portalnum]; //if the portal is already fully updated if (portal->frontcluster == clusternum) return qtrue; if (portal->backcluster == clusternum) return qtrue; //if the portal has no front cluster yet if (!portal->frontcluster) { portal->frontcluster = clusternum; } //end if //if the portal has no back cluster yet else if (!portal->backcluster) { portal->backcluster = clusternum; } //end else if else { //remove the cluster portal flag contents aasworld.areasettings[areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL; Log_Write("portal area %d is seperating more than two clusters\r\n", areanum); return qfalse; } //end else if (aasworld.portalindexsize >= AAS_MAX_PORTALINDEXSIZE) { AAS_Error("AAS_MAX_PORTALINDEXSIZE"); return qtrue; } //end if //set the area cluster number to the negative portal number aasworld.areasettings[areanum].cluster = -portalnum; //add the portal to the cluster using the portal index cluster = &aasworld.clusters[clusternum]; aasworld.portalindex[cluster->firstportal + cluster->numportals] = portalnum; aasworld.portalindexsize++; cluster->numportals++; return qtrue; } //end of the function AAS_UpdatePortal
// Ridah, multiple AAS worlds //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_SetCurrentWorld( int index ) { if ( index >= MAX_AAS_WORLDS || index < 0 ) { AAS_Error( "AAS_SetCurrentWorld: index out of range\n" ); return; } // set the current world pointer aasworld = &aasworlds[index]; }
//=========================================================================== // writes the current route-table data to a .rtb file in tne maps folder // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_RT_WriteRouteTable() { int ident, version; unsigned short crc_aas; fileHandle_t fp; char filename[MAX_QPATH]; // open the file for writing Com_sprintf(filename, MAX_QPATH, "maps/%s.rtb", (*aasworld).mapname); botimport.Print(PRT_MESSAGE, "\nsaving route-table to %s\n", filename); botimport.FS_FOpenFile(filename, &fp, FS_WRITE); if (!fp) { AAS_Error("Unable to open file: %s\n", filename); return; } // ident ident = LittleLong(RTBID); botimport.FS_Write(&ident, sizeof(ident), fp); // version version = LittleLong(RTBVERSION); botimport.FS_Write(&version, sizeof(version), fp); // crc crc_aas = CRC_ProcessString((unsigned char *)(*aasworld).areas, sizeof(aas_area_t) * (*aasworld).numareas); botimport.FS_Write(&crc_aas, sizeof(crc_aas), fp); // save the table data // children botimport.FS_Write(&(*aasworld).routetable->numChildren, sizeof(int), fp); botimport.FS_Write((*aasworld).routetable->children, (*aasworld).routetable->numChildren * sizeof(aas_rt_child_t), fp); // parents botimport.FS_Write(&(*aasworld).routetable->numParents, sizeof(int), fp); botimport.FS_Write((*aasworld).routetable->parents, (*aasworld).routetable->numParents * sizeof(aas_rt_parent_t), fp); // parentChildren botimport.FS_Write(&(*aasworld).routetable->numParentChildren, sizeof(int), fp); botimport.FS_Write((*aasworld).routetable->parentChildren, (*aasworld).routetable->numParentChildren * sizeof(unsigned short int), fp); // visibleParents botimport.FS_Write(&(*aasworld).routetable->numVisibleParents, sizeof(int), fp); botimport.FS_Write((*aasworld).routetable->visibleParents, (*aasworld).routetable->numVisibleParents * sizeof(unsigned short int), fp); // parentLinks botimport.FS_Write(&(*aasworld).routetable->numParentLinks, sizeof(int), fp); botimport.FS_Write((*aasworld).routetable->parentLinks, (*aasworld).routetable->numParentLinks * sizeof(aas_rt_parent_link_t), fp); botimport.FS_FCloseFile(fp); return; }
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_FloodCluster_r(int areanum, int clusternum) { int i, otherareanum; aas_face_t *face; aas_area_t *area; //set cluster mark aasworld.areasettings[areanum].cluster = clusternum; //if the area is a portal //if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) return; // area = &aasworld.areas[areanum]; //use area faces to flood into adjacent areas for (i = 0; i < area->numfaces; i++) { face = &aasworld.faces[abs(aasworld.faceindex[area->firstface + i])]; // if (face->frontarea != areanum) otherareanum = face->frontarea; else otherareanum = face->backarea; //if there's no area at the other side if (!otherareanum) continue; //if the area is a portal if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue; //if the area is already marked if (aasworld.areasettings[otherareanum].cluster) continue; // AAS_FloodCluster_r(otherareanum, clusternum); } //end for //use the reachabilities to flood into other areas for (i = 0; i < aasworld.areasettings[areanum].numreachableareas; i++) { otherareanum = aasworld.reachability[ aasworld.areasettings[areanum].firstreachablearea + i].areanum; if (!otherareanum) { continue; AAS_Error("reachability %d has zero area\n", aasworld.areasettings[areanum].firstreachablearea + i); } //end if //if the area is a portal if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue; //if the area is already marked if (aasworld.areasettings[otherareanum].cluster) continue; // AAS_FloodCluster_r(otherareanum, clusternum); } //end for } //end of the function AAS_FloodCluster_r
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_FindClusters(void) { int i; aas_cluster_t *cluster; AAS_RemoveClusterAreas(); // for (i = 1; i < aasworld.numareas; i++) { //if the area is already part of a cluster if (aasworld.areasettings[i].cluster) continue; // if not flooding through faces only use areas that have reachabilities if (nofaceflood) { if (!aasworld.areasettings[i].numreachableareas) continue; } //end if //if the area is a cluster portal if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL) continue; if (aasworld.numclusters >= AAS_MAX_CLUSTERS) { AAS_Error("AAS_MAX_CLUSTERS"); return qfalse; } //end if cluster = &aasworld.clusters[aasworld.numclusters]; cluster->numareas = 0; cluster->numreachabilityareas = 0; cluster->firstportal = aasworld.portalindexsize; cluster->numportals = 0; //flood the areas in this cluster if (!AAS_FloodClusterAreas_r(i, aasworld.numclusters)) return qfalse; if (!AAS_FloodClusterAreasUsingReachabilities(aasworld.numclusters)) return qfalse; //number the cluster areas //AAS_NumberClusterPortals(aasworld.numclusters); AAS_NumberClusterAreas(aasworld.numclusters); //Log_Write("cluster %d has %d areas\r\n", aasworld.numclusters, cluster->numareas); aasworld.numclusters++; } //end for return qtrue; } //end of the function AAS_FindClusters
//=========================================================================== // gets adjacent areas with less presence types recursively // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_GetAdjacentAreasWithLessPresenceTypes_r(int *areanums, int numareas, int curareanum) { int i, j, presencetype, otherpresencetype, otherareanum, facenum; aas_area_t *area; aas_face_t *face; areanums[numareas++] = curareanum; area = &aasworld.areas[curareanum]; presencetype = aasworld.areasettings[curareanum].presencetype; for (i = 0; i < area->numfaces; i++) { facenum = abs(aasworld.faceindex[area->firstface + i]); face = &aasworld.faces[facenum]; //if the face is solid if (face->faceflags & FACE_SOLID) continue; //the area at the other side of the face if (face->frontarea != curareanum) otherareanum = face->frontarea; else otherareanum = face->backarea; // otherpresencetype = aasworld.areasettings[otherareanum].presencetype; //if the other area has less presence types if ((presencetype & ~otherpresencetype) && !(otherpresencetype & ~presencetype)) { //check if the other area isn't already in the list for (j = 0; j < numareas; j++) { if (otherareanum == areanums[j]) break; } //end for //if the other area isn't already in the list if (j == numareas) { if (numareas >= MAX_PORTALAREAS) { AAS_Error("MAX_PORTALAREAS"); return numareas; } //end if numareas = AAS_GetAdjacentAreasWithLessPresenceTypes_r(areanums, numareas, otherareanum); } //end if } //end if } //end for return numareas; } //end of the function AAS_GetAdjacentAreasWithLessPresenceTypes_r
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_CreatePortals(void) { int i; aas_portal_t *portal; for (i = 1; i < aasworld.numareas; i++) { //if the area is a cluster portal if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL) { if (aasworld.numportals >= AAS_MAX_PORTALS) { AAS_Error("AAS_MAX_PORTALS"); return; } //end if portal = &aasworld.portals[aasworld.numportals]; portal->areanum = i; portal->frontcluster = 0; portal->backcluster = 0; aasworld.numportals++; } //end if } //end for } //end of the function AAS_CreatePortals
qboolean AAS_RT_ReadRouteTable(fileHandle_t fp) { int ident, version, i; unsigned short int crc, crc_aas; aas_rt_t *routetable; aas_rt_child_t *child; aas_rt_parent_t *parent; aas_rt_parent_link_t *plink; unsigned short int *psi; qboolean doswap; #ifdef DEBUG_READING_TIME int pretime; pretime = Sys_MilliSeconds(); #endif routetable = (*aasworld).routetable; doswap = (LittleLong(1) != 1); // check ident AAS_RT_DBG_Read(&ident, sizeof(ident), fp); ident = LittleLong(ident); if (ident != RTBID) { AAS_Error("File is not an RTB file\n"); botimport.FS_FCloseFile(fp); return qfalse; } // check version AAS_RT_DBG_Read(&version, sizeof(version), fp); version = LittleLong(version); if (version != RTBVERSION) { AAS_Error("File is version %i not %i\n", version, RTBVERSION); botimport.FS_FCloseFile(fp); return qfalse; } // read the CRC check on the AAS data AAS_RT_DBG_Read(&crc, sizeof(crc), fp); crc = LittleShort(crc); // calculate a CRC on the AAS areas crc_aas = CRC_ProcessString((unsigned char *)(*aasworld).areas, sizeof(aas_area_t) * (*aasworld).numareas); if (crc != crc_aas) { AAS_Error("Route-table is from different AAS file, ignoring.\n"); botimport.FS_FCloseFile(fp); return qfalse; } // read the route-table // children botimport.FS_Read(&routetable->numChildren, sizeof(int), fp); routetable->numChildren = LittleLong(routetable->numChildren); routetable->children = (aas_rt_child_t *) AAS_RT_GetClearedMemory(routetable->numChildren * sizeof(aas_rt_child_t)); botimport.FS_Read(routetable->children, routetable->numChildren * sizeof(aas_rt_child_t), fp); child = &routetable->children[0]; if (doswap) { for (i = 0; i < routetable->numChildren; i++, child++) { child->areanum = LittleShort(child->areanum); child->numParentLinks = LittleLong(child->numParentLinks); child->startParentLinks = LittleLong(child->startParentLinks); } } // parents botimport.FS_Read(&routetable->numParents, sizeof(int), fp); routetable->numParents = LittleLong(routetable->numParents); routetable->parents = (aas_rt_parent_t *) AAS_RT_GetClearedMemory(routetable->numParents * sizeof(aas_rt_parent_t)); botimport.FS_Read(routetable->parents, routetable->numParents * sizeof(aas_rt_parent_t), fp); parent = &routetable->parents[0]; if (doswap) { for (i = 0; i < routetable->numParents; i++, parent++) { parent->areanum = LittleShort(parent->areanum); parent->numParentChildren = LittleLong(parent->numParentChildren); parent->startParentChildren = LittleLong(parent->startParentChildren); parent->numVisibleParents = LittleLong(parent->numVisibleParents); parent->startVisibleParents = LittleLong(parent->startVisibleParents); } } // parentChildren botimport.FS_Read(&routetable->numParentChildren, sizeof(int), fp); routetable->numParentChildren = LittleLong(routetable->numParentChildren); routetable->parentChildren = (unsigned short int *) AAS_RT_GetClearedMemory(routetable->numParentChildren * sizeof(unsigned short int)); botimport.FS_Read(routetable->parentChildren, routetable->numParentChildren * sizeof(unsigned short int), fp); psi = &routetable->parentChildren[0]; if (doswap) { for (i = 0; i < routetable->numParentChildren; i++, psi++) { *psi = LittleShort(*psi); } } // visibleParents botimport.FS_Read(&routetable->numVisibleParents, sizeof(int), fp); routetable->numVisibleParents = LittleLong(routetable->numVisibleParents); routetable->visibleParents = (unsigned short int *) AAS_RT_GetClearedMemory(routetable->numVisibleParents * sizeof(unsigned short int)); botimport.FS_Read(routetable->visibleParents, routetable->numVisibleParents * sizeof(unsigned short int), fp); psi = &routetable->visibleParents[0]; if (doswap) { for (i = 0; i < routetable->numVisibleParents; i++, psi++) { *psi = LittleShort(*psi); } } // parentLinks botimport.FS_Read(&routetable->numParentLinks, sizeof(int), fp); routetable->numParentLinks = LittleLong(routetable->numParentLinks); routetable->parentLinks = (aas_rt_parent_link_t *) AAS_RT_GetClearedMemory(routetable->numParentLinks * sizeof(aas_rt_parent_link_t)); botimport.FS_Read(routetable->parentLinks, routetable->numParentLinks * sizeof(aas_parent_link_t), fp); plink = &routetable->parentLinks[0]; if (doswap) { for (i = 0; i < routetable->numParentLinks; i++, plink++) { plink->childIndex = LittleShort(plink->childIndex); plink->parent = LittleShort(plink->parent); } } // build the areaChildIndexes routetable->areaChildIndexes = (unsigned short int *) AAS_RT_GetClearedMemory((*aasworld).numareas * sizeof(unsigned short int)); child = routetable->children; for (i = 0; i < routetable->numChildren; i++, child++) { routetable->areaChildIndexes[child->areanum] = i + 1; } botimport.Print(PRT_MESSAGE, "Total Parents: %d\n", routetable->numParents); botimport.Print(PRT_MESSAGE, "Total Children: %d\n", routetable->numChildren); botimport.Print(PRT_MESSAGE, "Total Memory Used: %d\n", memorycount); #ifdef DEBUG_READING_TIME botimport.Print(PRT_MESSAGE, "Route-Table read time: %i\n", Sys_MilliSeconds() - pretime); #endif botimport.FS_FCloseFile(fp); return qtrue; }
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_FloodClusterAreas_r(int areanum, int clusternum) { aas_area_t *area; aas_face_t *face; int facenum, i; // if (areanum <= 0 || areanum >= aasworld.numareas) { AAS_Error("AAS_FloodClusterAreas_r: areanum out of range"); return qfalse; } //end if //if the area is already part of a cluster if (aasworld.areasettings[areanum].cluster > 0) { if (aasworld.areasettings[areanum].cluster == clusternum) return qtrue; // //there's a reachability going from one cluster to another only in one direction // AAS_Error("cluster %d touched cluster %d at area %d\r\n", clusternum, aasworld.areasettings[areanum].cluster, areanum); return qfalse; } //end if //don't add the cluster portal areas to the clusters if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) { return AAS_UpdatePortal(areanum, clusternum); } //end if //set the area cluster number aasworld.areasettings[areanum].cluster = clusternum; aasworld.areasettings[areanum].clusterareanum = aasworld.clusters[clusternum].numareas; //the cluster has an extra area aasworld.clusters[clusternum].numareas++; area = &aasworld.areas[areanum]; //use area faces to flood into adjacent areas if (!nofaceflood) { for (i = 0; i < area->numfaces; i++) { facenum = abs(aasworld.faceindex[area->firstface + i]); face = &aasworld.faces[facenum]; if (face->frontarea == areanum) { if (face->backarea) if (!AAS_FloodClusterAreas_r(face->backarea, clusternum)) return qfalse; } //end if else { if (face->frontarea) if (!AAS_FloodClusterAreas_r(face->frontarea, clusternum)) return qfalse; } //end else } //end for } //end if //use the reachabilities to flood into other areas for (i = 0; i < aasworld.areasettings[areanum].numreachableareas; i++) { if (!aasworld.reachability[ aasworld.areasettings[areanum].firstreachablearea + i].areanum) { continue; } //end if if (!AAS_FloodClusterAreas_r(aasworld.reachability[ aasworld.areasettings[areanum].firstreachablearea + i].areanum, clusternum)) return qfalse; } //end for return qtrue; } //end of the function AAS_FloodClusterAreas_r
//=========================================================================== // 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