summaryrefslogtreecommitdiff
path: root/ioq3-r437/src/server/sv_world.c
diff options
context:
space:
mode:
Diffstat (limited to 'ioq3-r437/src/server/sv_world.c')
-rw-r--r--ioq3-r437/src/server/sv_world.c691
1 files changed, 0 insertions, 691 deletions
diff --git a/ioq3-r437/src/server/sv_world.c b/ioq3-r437/src/server/sv_world.c
deleted file mode 100644
index e8485ce4..00000000
--- a/ioq3-r437/src/server/sv_world.c
+++ /dev/null
@@ -1,691 +0,0 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena 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 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// world.c -- world query functions
-
-#include "server.h"
-
-/*
-================
-SV_ClipHandleForEntity
-
-Returns a headnode that can be used for testing or clipping to a
-given entity. If the entity is a bsp model, the headnode will
-be returned, otherwise a custom box tree will be constructed.
-================
-*/
-clipHandle_t SV_ClipHandleForEntity( const sharedEntity_t *ent ) {
- if ( ent->r.bmodel ) {
- // explicit hulls in the BSP model
- return CM_InlineModel( ent->s.modelindex );
- }
- if ( ent->r.svFlags & SVF_CAPSULE ) {
- // create a temp capsule from bounding box sizes
- return CM_TempBoxModel( ent->r.mins, ent->r.maxs, qtrue );
- }
-
- // create a temp tree from bounding box sizes
- return CM_TempBoxModel( ent->r.mins, ent->r.maxs, qfalse );
-}
-
-
-
-/*
-===============================================================================
-
-ENTITY CHECKING
-
-To avoid linearly searching through lists of entities during environment testing,
-the world is carved up with an evenly spaced, axially aligned bsp tree. Entities
-are kept in chains either at the final leafs, or at the first node that splits
-them, which prevents having to deal with multiple fragments of a single entity.
-
-===============================================================================
-*/
-
-typedef struct worldSector_s {
- int axis; // -1 = leaf node
- float dist;
- struct worldSector_s *children[2];
- svEntity_t *entities;
-} worldSector_t;
-
-#define AREA_DEPTH 4
-#define AREA_NODES 64
-
-worldSector_t sv_worldSectors[AREA_NODES];
-int sv_numworldSectors;
-
-
-/*
-===============
-SV_SectorList_f
-===============
-*/
-void SV_SectorList_f( void ) {
- int i, c;
- worldSector_t *sec;
- svEntity_t *ent;
-
- for ( i = 0 ; i < AREA_NODES ; i++ ) {
- sec = &sv_worldSectors[i];
-
- c = 0;
- for ( ent = sec->entities ; ent ; ent = ent->nextEntityInWorldSector ) {
- c++;
- }
- Com_Printf( "sector %i: %i entities\n", i, c );
- }
-}
-
-/*
-===============
-SV_CreateworldSector
-
-Builds a uniformly subdivided tree for the given world size
-===============
-*/
-worldSector_t *SV_CreateworldSector( int depth, vec3_t mins, vec3_t maxs ) {
- worldSector_t *anode;
- vec3_t size;
- vec3_t mins1, maxs1, mins2, maxs2;
-
- anode = &sv_worldSectors[sv_numworldSectors];
- sv_numworldSectors++;
-
- if (depth == AREA_DEPTH) {
- anode->axis = -1;
- anode->children[0] = anode->children[1] = NULL;
- return anode;
- }
-
- VectorSubtract (maxs, mins, size);
- if (size[0] > size[1]) {
- anode->axis = 0;
- } else {
- anode->axis = 1;
- }
-
- anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
- VectorCopy (mins, mins1);
- VectorCopy (mins, mins2);
- VectorCopy (maxs, maxs1);
- VectorCopy (maxs, maxs2);
-
- maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
-
- anode->children[0] = SV_CreateworldSector (depth+1, mins2, maxs2);
- anode->children[1] = SV_CreateworldSector (depth+1, mins1, maxs1);
-
- return anode;
-}
-
-/*
-===============
-SV_ClearWorld
-
-===============
-*/
-void SV_ClearWorld( void ) {
- clipHandle_t h;
- vec3_t mins, maxs;
-
- Com_Memset( sv_worldSectors, 0, sizeof(sv_worldSectors) );
- sv_numworldSectors = 0;
-
- // get world map bounds
- h = CM_InlineModel( 0 );
- CM_ModelBounds( h, mins, maxs );
- SV_CreateworldSector( 0, mins, maxs );
-}
-
-
-/*
-===============
-SV_UnlinkEntity
-
-===============
-*/
-void SV_UnlinkEntity( sharedEntity_t *gEnt ) {
- svEntity_t *ent;
- svEntity_t *scan;
- worldSector_t *ws;
-
- ent = SV_SvEntityForGentity( gEnt );
-
- gEnt->r.linked = qfalse;
-
- ws = ent->worldSector;
- if ( !ws ) {
- return; // not linked in anywhere
- }
- ent->worldSector = NULL;
-
- if ( ws->entities == ent ) {
- ws->entities = ent->nextEntityInWorldSector;
- return;
- }
-
- for ( scan = ws->entities ; scan ; scan = scan->nextEntityInWorldSector ) {
- if ( scan->nextEntityInWorldSector == ent ) {
- scan->nextEntityInWorldSector = ent->nextEntityInWorldSector;
- return;
- }
- }
-
- Com_Printf( "WARNING: SV_UnlinkEntity: not found in worldSector\n" );
-}
-
-
-/*
-===============
-SV_LinkEntity
-
-===============
-*/
-#define MAX_TOTAL_ENT_LEAFS 128
-void SV_LinkEntity( sharedEntity_t *gEnt ) {
- worldSector_t *node;
- int leafs[MAX_TOTAL_ENT_LEAFS];
- int cluster;
- int num_leafs;
- int i, j, k;
- int area;
- int lastLeaf;
- float *origin, *angles;
- svEntity_t *ent;
-
- ent = SV_SvEntityForGentity( gEnt );
-
- if ( ent->worldSector ) {
- SV_UnlinkEntity( gEnt ); // unlink from old position
- }
-
- // encode the size into the entityState_t for client prediction
- if ( gEnt->r.bmodel ) {
- gEnt->s.solid = SOLID_BMODEL; // a solid_box will never create this value
- } else if ( gEnt->r.contents & ( CONTENTS_SOLID | CONTENTS_BODY ) ) {
- // assume that x/y are equal and symetric
- i = gEnt->r.maxs[0];
- if (i<1)
- i = 1;
- if (i>255)
- i = 255;
-
- // z is not symetric
- j = (-gEnt->r.mins[2]);
- if (j<1)
- j = 1;
- if (j>255)
- j = 255;
-
- // and z maxs can be negative...
- k = (gEnt->r.maxs[2]+32);
- if (k<1)
- k = 1;
- if (k>255)
- k = 255;
-
- gEnt->s.solid = (k<<16) | (j<<8) | i;
- } else {
- gEnt->s.solid = 0;
- }
-
- // get the position
- origin = gEnt->r.currentOrigin;
- angles = gEnt->r.currentAngles;
-
- // set the abs box
- if ( gEnt->r.bmodel && (angles[0] || angles[1] || angles[2]) ) {
- // expand for rotation
- float max;
- int i;
-
- max = RadiusFromBounds( gEnt->r.mins, gEnt->r.maxs );
- for (i=0 ; i<3 ; i++) {
- gEnt->r.absmin[i] = origin[i] - max;
- gEnt->r.absmax[i] = origin[i] + max;
- }
- } else {
- // normal
- VectorAdd (origin, gEnt->r.mins, gEnt->r.absmin);
- VectorAdd (origin, gEnt->r.maxs, gEnt->r.absmax);
- }
-
- // because movement is clipped an epsilon away from an actual edge,
- // we must fully check even when bounding boxes don't quite touch
- gEnt->r.absmin[0] -= 1;
- gEnt->r.absmin[1] -= 1;
- gEnt->r.absmin[2] -= 1;
- gEnt->r.absmax[0] += 1;
- gEnt->r.absmax[1] += 1;
- gEnt->r.absmax[2] += 1;
-
- // link to PVS leafs
- ent->numClusters = 0;
- ent->lastCluster = 0;
- ent->areanum = -1;
- ent->areanum2 = -1;
-
- //get all leafs, including solids
- num_leafs = CM_BoxLeafnums( gEnt->r.absmin, gEnt->r.absmax,
- leafs, MAX_TOTAL_ENT_LEAFS, &lastLeaf );
-
- // if none of the leafs were inside the map, the
- // entity is outside the world and can be considered unlinked
- if ( !num_leafs ) {
- return;
- }
-
- // set areas, even from clusters that don't fit in the entity array
- for (i=0 ; i<num_leafs ; i++) {
- area = CM_LeafArea (leafs[i]);
- if (area != -1) {
- // doors may legally straggle two areas,
- // but nothing should evern need more than that
- if (ent->areanum != -1 && ent->areanum != area) {
- if (ent->areanum2 != -1 && ent->areanum2 != area && sv.state == SS_LOADING) {
- Com_DPrintf ("Object %i touching 3 areas at %f %f %f\n",
- gEnt->s.number,
- gEnt->r.absmin[0], gEnt->r.absmin[1], gEnt->r.absmin[2]);
- }
- ent->areanum2 = area;
- } else {
- ent->areanum = area;
- }
- }
- }
-
- // store as many explicit clusters as we can
- ent->numClusters = 0;
- for (i=0 ; i < num_leafs ; i++) {
- cluster = CM_LeafCluster( leafs[i] );
- if ( cluster != -1 ) {
- ent->clusternums[ent->numClusters++] = cluster;
- if ( ent->numClusters == MAX_ENT_CLUSTERS ) {
- break;
- }
- }
- }
-
- // store off a last cluster if we need to
- if ( i != num_leafs ) {
- ent->lastCluster = CM_LeafCluster( lastLeaf );
- }
-
- gEnt->r.linkcount++;
-
- // find the first world sector node that the ent's box crosses
- node = sv_worldSectors;
- while (1)
- {
- if (node->axis == -1)
- break;
- if ( gEnt->r.absmin[node->axis] > node->dist)
- node = node->children[0];
- else if ( gEnt->r.absmax[node->axis] < node->dist)
- node = node->children[1];
- else
- break; // crosses the node
- }
-
- // link it in
- ent->worldSector = node;
- ent->nextEntityInWorldSector = node->entities;
- node->entities = ent;
-
- gEnt->r.linked = qtrue;
-}
-
-/*
-============================================================================
-
-AREA QUERY
-
-Fills in a list of all entities who's absmin / absmax intersects the given
-bounds. This does NOT mean that they actually touch in the case of bmodels.
-============================================================================
-*/
-
-typedef struct {
- const float *mins;
- const float *maxs;
- int *list;
- int count, maxcount;
-} areaParms_t;
-
-
-/*
-====================
-SV_AreaEntities_r
-
-====================
-*/
-void SV_AreaEntities_r( worldSector_t *node, areaParms_t *ap ) {
- svEntity_t *check, *next;
- sharedEntity_t *gcheck;
- int count;
-
- count = 0;
-
- for ( check = node->entities ; check ; check = next ) {
- next = check->nextEntityInWorldSector;
-
- gcheck = SV_GEntityForSvEntity( check );
-
- if ( gcheck->r.absmin[0] > ap->maxs[0]
- || gcheck->r.absmin[1] > ap->maxs[1]
- || gcheck->r.absmin[2] > ap->maxs[2]
- || gcheck->r.absmax[0] < ap->mins[0]
- || gcheck->r.absmax[1] < ap->mins[1]
- || gcheck->r.absmax[2] < ap->mins[2]) {
- continue;
- }
-
- if ( ap->count == ap->maxcount ) {
- Com_Printf ("SV_AreaEntities: MAXCOUNT\n");
- return;
- }
-
- ap->list[ap->count] = check - sv.svEntities;
- ap->count++;
- }
-
- if (node->axis == -1) {
- return; // terminal node
- }
-
- // recurse down both sides
- if ( ap->maxs[node->axis] > node->dist ) {
- SV_AreaEntities_r ( node->children[0], ap );
- }
- if ( ap->mins[node->axis] < node->dist ) {
- SV_AreaEntities_r ( node->children[1], ap );
- }
-}
-
-/*
-================
-SV_AreaEntities
-================
-*/
-int SV_AreaEntities( const vec3_t mins, const vec3_t maxs, int *entityList, int maxcount ) {
- areaParms_t ap;
-
- ap.mins = mins;
- ap.maxs = maxs;
- ap.list = entityList;
- ap.count = 0;
- ap.maxcount = maxcount;
-
- SV_AreaEntities_r( sv_worldSectors, &ap );
-
- return ap.count;
-}
-
-
-
-//===========================================================================
-
-
-typedef struct {
- vec3_t boxmins, boxmaxs;// enclose the test object along entire move
- const float *mins;
- const float *maxs; // size of the moving object
- const float *start;
- vec3_t end;
- trace_t trace;
- int passEntityNum;
- int contentmask;
- int capsule;
-} moveclip_t;
-
-
-/*
-====================
-SV_ClipToEntity
-
-====================
-*/
-void SV_ClipToEntity( trace_t *trace, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int entityNum, int contentmask, int capsule ) {
- sharedEntity_t *touch;
- clipHandle_t clipHandle;
- float *origin, *angles;
-
- touch = SV_GentityNum( entityNum );
-
- Com_Memset(trace, 0, sizeof(trace_t));
-
- // if it doesn't have any brushes of a type we
- // are looking for, ignore it
- if ( ! ( contentmask & touch->r.contents ) ) {
- trace->fraction = 1.0;
- return;
- }
-
- // might intersect, so do an exact clip
- clipHandle = SV_ClipHandleForEntity (touch);
-
- origin = touch->r.currentOrigin;
- angles = touch->r.currentAngles;
-
- if ( !touch->r.bmodel ) {
- angles = vec3_origin; // boxes don't rotate
- }
-
- CM_TransformedBoxTrace ( trace, (float *)start, (float *)end,
- (float *)mins, (float *)maxs, clipHandle, contentmask,
- origin, angles, capsule);
-
- if ( trace->fraction < 1 ) {
- trace->entityNum = touch->s.number;
- }
-}
-
-
-/*
-====================
-SV_ClipMoveToEntities
-
-====================
-*/
-void SV_ClipMoveToEntities( moveclip_t *clip ) {
- int i, num;
- int touchlist[MAX_GENTITIES];
- sharedEntity_t *touch;
- int passOwnerNum;
- trace_t trace;
- clipHandle_t clipHandle;
- float *origin, *angles;
-
- num = SV_AreaEntities( clip->boxmins, clip->boxmaxs, touchlist, MAX_GENTITIES);
-
- if ( clip->passEntityNum != ENTITYNUM_NONE ) {
- passOwnerNum = ( SV_GentityNum( clip->passEntityNum ) )->r.ownerNum;
- if ( passOwnerNum == ENTITYNUM_NONE ) {
- passOwnerNum = -1;
- }
- } else {
- passOwnerNum = -1;
- }
-
- for ( i=0 ; i<num ; i++ ) {
- if ( clip->trace.allsolid ) {
- return;
- }
- touch = SV_GentityNum( touchlist[i] );
-
- // see if we should ignore this entity
- if ( clip->passEntityNum != ENTITYNUM_NONE ) {
- if ( touchlist[i] == clip->passEntityNum ) {
- continue; // don't clip against the pass entity
- }
- if ( touch->r.ownerNum == clip->passEntityNum ) {
- continue; // don't clip against own missiles
- }
- if ( touch->r.ownerNum == passOwnerNum ) {
- continue; // don't clip against other missiles from our owner
- }
- }
-
- // if it doesn't have any brushes of a type we
- // are looking for, ignore it
- if ( ! ( clip->contentmask & touch->r.contents ) ) {
- continue;
- }
-
- // might intersect, so do an exact clip
- clipHandle = SV_ClipHandleForEntity (touch);
-
- origin = touch->r.currentOrigin;
- angles = touch->r.currentAngles;
-
-
- if ( !touch->r.bmodel ) {
- angles = vec3_origin; // boxes don't rotate
- }
-
- CM_TransformedBoxTrace ( &trace, (float *)clip->start, (float *)clip->end,
- (float *)clip->mins, (float *)clip->maxs, clipHandle, clip->contentmask,
- origin, angles, clip->capsule);
-
- if ( trace.allsolid ) {
- clip->trace.allsolid = qtrue;
- trace.entityNum = touch->s.number;
- } else if ( trace.startsolid ) {
- clip->trace.startsolid = qtrue;
- trace.entityNum = touch->s.number;
- }
-
- if ( trace.fraction < clip->trace.fraction ) {
- qboolean oldStart;
-
- // make sure we keep a startsolid from a previous trace
- oldStart = clip->trace.startsolid;
-
- trace.entityNum = touch->s.number;
- clip->trace = trace;
- clip->trace.startsolid |= oldStart;
- }
- }
-}
-
-
-/*
-==================
-SV_Trace
-
-Moves the given mins/maxs volume through the world from start to end.
-passEntityNum and entities owned by passEntityNum are explicitly not checked.
-==================
-*/
-void SV_Trace( trace_t *results, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask, int capsule ) {
- moveclip_t clip;
- int i;
-
- if ( !mins ) {
- mins = vec3_origin;
- }
- if ( !maxs ) {
- maxs = vec3_origin;
- }
-
- Com_Memset ( &clip, 0, sizeof ( moveclip_t ) );
-
- // clip to world
- CM_BoxTrace( &clip.trace, start, end, mins, maxs, 0, contentmask, capsule );
- clip.trace.entityNum = clip.trace.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
- if ( clip.trace.fraction == 0 ) {
- *results = clip.trace;
- return; // blocked immediately by the world
- }
-
- clip.contentmask = contentmask;
- clip.start = start;
-// VectorCopy( clip.trace.endpos, clip.end );
- VectorCopy( end, clip.end );
- clip.mins = mins;
- clip.maxs = maxs;
- clip.passEntityNum = passEntityNum;
- clip.capsule = capsule;
-
- // create the bounding box of the entire move
- // we can limit it to the part of the move not
- // already clipped off by the world, which can be
- // a significant savings for line of sight and shot traces
- for ( i=0 ; i<3 ; i++ ) {
- if ( end[i] > start[i] ) {
- clip.boxmins[i] = clip.start[i] + clip.mins[i] - 1;
- clip.boxmaxs[i] = clip.end[i] + clip.maxs[i] + 1;
- } else {
- clip.boxmins[i] = clip.end[i] + clip.mins[i] - 1;
- clip.boxmaxs[i] = clip.start[i] + clip.maxs[i] + 1;
- }
- }
-
- // clip to other solid entities
- SV_ClipMoveToEntities ( &clip );
-
- *results = clip.trace;
-}
-
-
-
-/*
-=============
-SV_PointContents
-=============
-*/
-int SV_PointContents( const vec3_t p, int passEntityNum ) {
- int touch[MAX_GENTITIES];
- sharedEntity_t *hit;
- int i, num;
- int contents, c2;
- clipHandle_t clipHandle;
- float *angles;
-
- // get base contents from world
- contents = CM_PointContents( p, 0 );
-
- // or in contents from all the other entities
- num = SV_AreaEntities( p, p, touch, MAX_GENTITIES );
-
- for ( i=0 ; i<num ; i++ ) {
- if ( touch[i] == passEntityNum ) {
- continue;
- }
- hit = SV_GentityNum( touch[i] );
- // might intersect, so do an exact clip
- clipHandle = SV_ClipHandleForEntity( hit );
- angles = hit->s.angles;
- if ( !hit->r.bmodel ) {
- angles = vec3_origin; // boxes don't rotate
- }
-
- c2 = CM_TransformedPointContents (p, clipHandle, hit->s.origin, hit->s.angles);
-
- contents |= c2;
- }
-
- return contents;
-}
-
-