/* =========================================================================== 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 . 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: be_aas_entity.c * * desc: AAS entities * * *****************************************************************************/ #include "../game/q_shared.h" #include "l_memory.h" #include "l_script.h" #include "l_precomp.h" #include "l_struct.h" #include "l_utils.h" #include "l_log.h" #include "aasfile.h" #include "../game/botlib.h" #include "../game/be_aas.h" #include "be_aas_funcs.h" #include "be_interface.h" #include "be_aas_def.h" #define MASK_SOLID CONTENTS_PLAYERCLIP // Ridah, always use the default world for entities extern aas_t aasworlds[2]; aas_t *defaultaasworld = aasworlds; //FIXME: these might change enum { ET_GENERAL, ET_PLAYER, ET_ITEM, ET_MISSILE, ET_MOVER }; //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_UpdateEntity( int entnum, bot_entitystate_t *state ) { int relink; aas_entity_t *ent; vec3_t absmins, absmaxs; if ( !( *defaultaasworld ).loaded ) { botimport.Print( PRT_MESSAGE, "AAS_UpdateEntity: not loaded\n" ); return BLERR_NOAASFILE; } //end if ent = &( *defaultaasworld ).entities[entnum]; ent->i.update_time = AAS_Time() - ent->i.ltime; ent->i.type = state->type; ent->i.flags = state->flags; ent->i.ltime = AAS_Time(); VectorCopy( ent->i.origin, ent->i.lastvisorigin ); VectorCopy( state->old_origin, ent->i.old_origin ); ent->i.solid = state->solid; ent->i.groundent = state->groundent; ent->i.modelindex = state->modelindex; ent->i.modelindex2 = state->modelindex2; ent->i.frame = state->frame; //ent->i.event = state->event; ent->i.eventParm = state->eventParm; ent->i.powerups = state->powerups; ent->i.weapon = state->weapon; ent->i.legsAnim = state->legsAnim; ent->i.torsoAnim = state->torsoAnim; // ent->i.weapAnim = state->weapAnim; //----(SA) //----(SA) didn't want to comment in as I wasn't sure of any implications of changing the aas_entityinfo_t and bot_entitystate_t structures. //number of the entity ent->i.number = entnum; //updated so set valid flag ent->i.valid = qtrue; //link everything the first frame if ( ( *defaultaasworld ).numframes == 1 ) { relink = qtrue; } else { relink = qfalse;} // if ( ent->i.solid == SOLID_BSP ) { //if the angles of the model changed if ( !VectorCompare( state->angles, ent->i.angles ) ) { VectorCopy( state->angles, ent->i.angles ); relink = qtrue; } //end if //get the mins and maxs of the model //FIXME: rotate mins and maxs AAS_BSPModelMinsMaxsOrigin( ent->i.modelindex, ent->i.angles, ent->i.mins, ent->i.maxs, NULL ); } //end if else if ( ent->i.solid == SOLID_BBOX ) { //if the bounding box size changed if ( !VectorCompare( state->mins, ent->i.mins ) || !VectorCompare( state->maxs, ent->i.maxs ) ) { VectorCopy( state->mins, ent->i.mins ); VectorCopy( state->maxs, ent->i.maxs ); relink = qtrue; } //end if } //end if //if the origin changed if ( !VectorCompare( state->origin, ent->i.origin ) ) { VectorCopy( state->origin, ent->i.origin ); relink = qtrue; } //end if //if the entity should be relinked if ( relink ) { //don't link the world model if ( entnum != ENTITYNUM_WORLD ) { //absolute mins and maxs VectorAdd( ent->i.mins, ent->i.origin, absmins ); VectorAdd( ent->i.maxs, ent->i.origin, absmaxs ); //unlink the entity AAS_UnlinkFromAreas( ent->areas ); //relink the entity to the AAS areas (use the larges bbox) ent->areas = AAS_LinkEntityClientBBox( absmins, absmaxs, entnum, PRESENCE_NORMAL ); //unlink the entity from the BSP leaves AAS_UnlinkFromBSPLeaves( ent->leaves ); //link the entity to the world BSP tree ent->leaves = AAS_BSPLinkEntity( absmins, absmaxs, entnum, 0 ); } //end if } //end if return BLERR_NOERROR; } //end of the function AAS_UpdateEntity //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_EntityInfo( int entnum, aas_entityinfo_t *info ) { if ( !( *defaultaasworld ).initialized ) { botimport.Print( PRT_FATAL, "AAS_EntityInfo: (*defaultaasworld) not initialized\n" ); memset( info, 0, sizeof( aas_entityinfo_t ) ); return; } //end if if ( entnum < 0 || entnum >= ( *defaultaasworld ).maxentities ) { botimport.Print( PRT_FATAL, "AAS_EntityInfo: entnum %d out of range\n", entnum ); memset( info, 0, sizeof( aas_entityinfo_t ) ); return; } //end if memcpy( info, &( *defaultaasworld ).entities[entnum].i, sizeof( aas_entityinfo_t ) ); } //end of the function AAS_EntityInfo //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_EntityOrigin( int entnum, vec3_t origin ) { if ( entnum < 0 || entnum >= ( *defaultaasworld ).maxentities ) { botimport.Print( PRT_FATAL, "AAS_EntityOrigin: entnum %d out of range\n", entnum ); VectorClear( origin ); return; } //end if VectorCopy( ( *defaultaasworld ).entities[entnum].i.origin, origin ); } //end of the function AAS_EntityOrigin //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_EntityModelindex( int entnum ) { if ( entnum < 0 || entnum >= ( *defaultaasworld ).maxentities ) { botimport.Print( PRT_FATAL, "AAS_EntityModelindex: entnum %d out of range\n", entnum ); return 0; } //end if return ( *defaultaasworld ).entities[entnum].i.modelindex; } //end of the function AAS_EntityModelindex //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_EntityType( int entnum ) { if ( !( *defaultaasworld ).initialized ) { return 0; } if ( entnum < 0 || entnum >= ( *defaultaasworld ).maxentities ) { botimport.Print( PRT_FATAL, "AAS_EntityType: entnum %d out of range\n", entnum ); return 0; } //end if return ( *defaultaasworld ).entities[entnum].i.type; } //end of the AAS_EntityType //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_EntityModelNum( int entnum ) { if ( !( *defaultaasworld ).initialized ) { return 0; } if ( entnum < 0 || entnum >= ( *defaultaasworld ).maxentities ) { botimport.Print( PRT_FATAL, "AAS_EntityModelNum: entnum %d out of range\n", entnum ); return 0; } //end if return ( *defaultaasworld ).entities[entnum].i.modelindex; } //end of the function AAS_EntityModelNum //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_OriginOfEntityWithModelNum( int modelnum, vec3_t origin ) { int i; aas_entity_t *ent; for ( i = 0; i < ( *defaultaasworld ).maxentities; i++ ) { ent = &( *defaultaasworld ).entities[i]; if ( ent->i.type == ET_MOVER ) { if ( ent->i.modelindex == modelnum ) { VectorCopy( ent->i.origin, origin ); return qtrue; } //end if } } //end for return qfalse; } //end of the function AAS_OriginOfEntityWithModelNum //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_EntitySize( int entnum, vec3_t mins, vec3_t maxs ) { aas_entity_t *ent; if ( !( *defaultaasworld ).initialized ) { return; } if ( entnum < 0 || entnum >= ( *defaultaasworld ).maxentities ) { botimport.Print( PRT_FATAL, "AAS_EntitySize: entnum %d out of range\n", entnum ); return; } //end if ent = &( *defaultaasworld ).entities[entnum]; VectorCopy( ent->i.mins, mins ); VectorCopy( ent->i.maxs, maxs ); } //end of the function AAS_EntitySize //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_EntityBSPData( int entnum, bsp_entdata_t *entdata ) { aas_entity_t *ent; ent = &( *defaultaasworld ).entities[entnum]; VectorCopy( ent->i.origin, entdata->origin ); VectorCopy( ent->i.angles, entdata->angles ); VectorAdd( ent->i.origin, ent->i.mins, entdata->absmins ); VectorAdd( ent->i.origin, ent->i.maxs, entdata->absmaxs ); entdata->solid = ent->i.solid; entdata->modelnum = ent->i.modelindex - 1; } //end of the function AAS_EntityBSPData //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_ResetEntityLinks( void ) { int i; for ( i = 0; i < ( *defaultaasworld ).maxentities; i++ ) { ( *defaultaasworld ).entities[i].areas = NULL; ( *defaultaasworld ).entities[i].leaves = NULL; } //end for } //end of the function AAS_ResetEntityLinks //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_InvalidateEntities( void ) { int i; for ( i = 0; i < ( *defaultaasworld ).maxentities; i++ ) { ( *defaultaasworld ).entities[i].i.valid = qfalse; ( *defaultaasworld ).entities[i].i.number = i; } //end for } //end of the function AAS_InvalidateEntities //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_NearestEntity( vec3_t origin, int modelindex ) { int i, bestentnum; float dist, bestdist; aas_entity_t *ent; vec3_t dir; bestentnum = 0; bestdist = 99999; for ( i = 0; i < ( *defaultaasworld ).maxentities; i++ ) { ent = &( *defaultaasworld ).entities[i]; if ( ent->i.modelindex != modelindex ) { continue; } VectorSubtract( ent->i.origin, origin, dir ); if ( abs( dir[0] ) < 40 ) { if ( abs( dir[1] ) < 40 ) { dist = VectorLength( dir ); if ( dist < bestdist ) { bestdist = dist; bestentnum = i; } //end if } //end if } //end if } //end for return bestentnum; } //end of the function AAS_NearestEntity //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_BestReachableEntityArea( int entnum ) { aas_entity_t *ent; ent = &( *defaultaasworld ).entities[entnum]; return AAS_BestReachableLinkArea( ent->areas ); } //end of the function AAS_BestReachableEntityArea //=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== int AAS_NextEntity( int entnum ) { if ( !( *defaultaasworld ).loaded ) { return 0; } if ( entnum < 0 ) { entnum = -1; } while ( ++entnum < ( *defaultaasworld ).maxentities ) { if ( ( *defaultaasworld ).entities[entnum].i.valid ) { return entnum; } } //end while return 0; } //end of the function AAS_NextEntity // Ridah, used to find out if there is an entity touching the given area, if so, try and avoid it /* ============ AAS_EntityInArea ============ */ int AAS_IsEntityInArea( int entnumIgnore, int entnumIgnore2, int areanum ) { aas_link_t *link; aas_entity_t *ent; // int i; for ( link = ( *aasworld ).arealinkedentities[areanum]; link; link = link->next_ent ) { //ignore the pass entity if ( link->entnum == entnumIgnore ) { continue; } if ( link->entnum == entnumIgnore2 ) { continue; } // ent = &( *defaultaasworld ).entities[link->entnum]; if ( !ent->i.valid ) { continue; } if ( !ent->i.solid ) { continue; } return qtrue; } /* ent = (*defaultaasworld).entities; for (i = 0; i < (*defaultaasworld).maxclients; i++, ent++) { if (!ent->i.valid) continue; if (!ent->i.solid) continue; if (i == entnumIgnore) continue; if (i == entnumIgnore2) continue; for (link = ent->areas; link; link = link->next_area) { if (link->areanum == areanum) { return qtrue; } //end if } //end for } */ return qfalse; } /* ============= AAS_SetAASBlockingEntity ============= */ int AAS_EnableRoutingArea( int areanum, int enable ); void AAS_SetAASBlockingEntity( vec3_t absmin, vec3_t absmax, qboolean blocking ) { int areas[128]; int numareas, i, w; // // check for resetting AAS blocking // TTimo WTF?? qboolean blocking // warning: comparison is always false due to limited range of data type // if (VectorCompare( absmin, absmax ) && blocking < 0) { if ( VectorCompare( absmin, absmax ) && !blocking ) { for ( w = 0; w < MAX_AAS_WORLDS; w++ ) { AAS_SetCurrentWorld( w ); // if ( !( *aasworld ).loaded ) { continue; } // now clear blocking status for ( i = 1; i < ( *aasworld ).numareas; i++ ) { AAS_EnableRoutingArea( i, qtrue ); } } // return; } // for ( w = 0; w < MAX_AAS_WORLDS; w++ ) { AAS_SetCurrentWorld( w ); // if ( !( *aasworld ).loaded ) { continue; } // grab the list of areas numareas = AAS_BBoxAreas( absmin, absmax, areas, 128 ); // now set their blocking status for ( i = 0; i < numareas; i++ ) { AAS_EnableRoutingArea( areas[i], !blocking ); } } }