This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/engine/server/sv_world.c

667 lines
17 KiB
C
Raw Normal View History

2008-11-14 22:00:00 +01:00
//=======================================================================
// Copyright XashXT Group 2008 <20>
// sv_world.c - world query functions
//=======================================================================
2007-06-21 22:00:00 +02:00
2008-06-09 22:00:00 +02:00
#include "common.h"
2007-06-21 22:00:00 +02:00
#include "server.h"
2008-09-09 22:00:00 +02:00
#include "const.h"
2009-11-10 22:00:00 +01:00
#include "pm_defs.h"
2007-06-21 22:00:00 +02:00
2008-11-14 22:00:00 +01:00
areanode_t sv_areanodes[AREA_NODES];
int sv_numareanodes;
2007-06-21 22:00:00 +02:00
2008-11-14 22:00:00 +01:00
/*
===============
SV_CreateAreaNode
builds a uniformly subdivided tree for the given world size
===============
*/
areanode_t *SV_CreateAreaNode( int depth, vec3_t mins, vec3_t maxs )
{
areanode_t *anode;
2007-06-21 22:00:00 +02:00
vec3_t size;
2008-11-14 22:00:00 +01:00
vec3_t mins1, maxs1;
vec3_t mins2, maxs2;
2007-06-21 22:00:00 +02:00
2008-11-14 22:00:00 +01:00
anode = &sv_areanodes[sv_numareanodes++];
2007-06-21 22:00:00 +02:00
2009-11-02 22:00:00 +01:00
ClearLink( &anode->trigger_edicts );
ClearLink( &anode->solid_edicts );
2008-11-14 22:00:00 +01:00
2008-01-17 22:00:00 +01:00
if( depth == AREA_DEPTH )
2007-06-21 22:00:00 +02:00
{
anode->axis = -1;
anode->children[0] = anode->children[1] = NULL;
return anode;
}
2008-01-17 22:00:00 +01:00
VectorSubtract( maxs, mins, size );
2008-11-14 22:00:00 +01:00
if( size[0] > size[1] )
anode->axis = 0;
2007-09-16 22:00:00 +02:00
else anode->axis = 1;
2008-11-14 22:00:00 +01:00
2008-01-17 22:00:00 +01:00
anode->dist = 0.5f * (maxs[anode->axis] + mins[anode->axis]);
2008-11-14 22:00:00 +01:00
VectorCopy( mins, mins1 );
VectorCopy( mins, mins2 );
VectorCopy( maxs, maxs1 );
VectorCopy( maxs, maxs2 );
2007-06-21 22:00:00 +02:00
maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
2008-11-14 22:00:00 +01:00
anode->children[0] = SV_CreateAreaNode( depth+1, mins2, maxs2 );
anode->children[1] = SV_CreateAreaNode( depth+1, mins1, maxs1 );
2007-06-21 22:00:00 +02:00
return anode;
}
/*
===============
SV_ClearWorld
===============
*/
2008-09-09 22:00:00 +02:00
void SV_ClearWorld( void )
2007-06-21 22:00:00 +02:00
{
2009-10-28 22:00:00 +01:00
vec3_t mins, maxs;
2009-10-29 22:00:00 +01:00
int worldIndex = 1;
2008-11-14 22:00:00 +01:00
sv_numareanodes = 0;
2009-10-29 22:00:00 +01:00
Mod_GetBounds( worldIndex, mins, maxs );
2008-11-14 22:00:00 +01:00
Mem_Set( sv_areanodes, 0, sizeof( sv_areanodes ));
2009-10-28 22:00:00 +01:00
SV_CreateAreaNode( 0, mins, maxs );
2007-06-21 22:00:00 +02:00
}
2009-11-02 22:00:00 +01:00
/*
====================
SV_TouchLinks
====================
*/
void SV_TouchLinks( edict_t *ent, areanode_t *node )
{
link_t *l, *next;
edict_t *touch;
// touch linked edicts
for( l = node->trigger_edicts.next; l != &node->trigger_edicts; l = next )
{
next = l->next;
touch = EDICT_FROM_AREA( l );
if( touch == ent ) continue;
if( touch->free || touch->v.solid != SOLID_TRIGGER )
continue;
if( !BoundsIntersect( ent->v.absmin, ent->v.absmax, touch->v.absmin, touch->v.absmax ))
continue;
svgame.globals->time = sv.time * 0.001f;
svgame.dllFuncs.pfnTouch( touch, ent );
if( ent->free ) break; // killtarget issues
}
// recurse down both sides
if( node->axis == -1 ) return;
if( ent->v.absmax[node->axis] > node->dist )
SV_TouchLinks( ent, node->children[0] );
if( ent->v.absmin[node->axis] < node->dist )
SV_TouchLinks( ent, node->children[1] );
}
2007-06-21 22:00:00 +02:00
/*
===============
SV_UnlinkEdict
===============
*/
2008-01-17 22:00:00 +01:00
void SV_UnlinkEdict( edict_t *ent )
2007-06-21 22:00:00 +02:00
{
2008-11-14 22:00:00 +01:00
// not linked in anywhere
2009-11-02 22:00:00 +01:00
if( !ent->pvServerData->area.prev )
return;
2008-01-17 22:00:00 +01:00
2009-11-02 22:00:00 +01:00
RemoveLink( &ent->pvServerData->area );
ent->pvServerData->area.prev = NULL;
ent->pvServerData->area.next = NULL;
2009-11-26 22:00:00 +01:00
ent->pvServerData->linked = false;
2008-01-17 22:00:00 +01:00
}
2007-06-21 22:00:00 +02:00
/*
===============
2008-01-17 22:00:00 +01:00
SV_LinkEntity
2007-06-21 22:00:00 +02:00
===============
*/
2009-11-02 22:00:00 +01:00
void SV_LinkEdict( edict_t *ent, bool touch_triggers )
2007-06-21 22:00:00 +02:00
{
2008-11-14 22:00:00 +01:00
areanode_t *node;
2007-09-16 22:00:00 +02:00
int leafs[MAX_TOTAL_ENT_LEAFS];
2009-11-10 22:00:00 +01:00
int clusters[MAX_TOTAL_ENT_LEAFS];
2007-09-16 22:00:00 +02:00
int num_leafs;
2009-11-10 22:00:00 +01:00
int i, j;
int area;
int lastleaf;
2008-12-26 22:00:00 +01:00
sv_priv_t *sv_ent;
2008-01-17 22:00:00 +01:00
2008-12-26 22:00:00 +01:00
sv_ent = ent->pvServerData;
2007-09-06 22:00:00 +02:00
2009-01-04 22:00:00 +01:00
if( !sv_ent ) return;
2008-11-14 22:00:00 +01:00
if( sv_ent->area.prev ) SV_UnlinkEdict( ent ); // unlink from old position
2008-12-17 22:00:00 +01:00
if( ent == EDICT_NUM( 0 )) return; // don't add the world
2008-12-15 22:00:00 +01:00
if( ent->free ) return;
2007-06-21 22:00:00 +02:00
2009-01-04 22:00:00 +01:00
// trying to classify unclassified edicts
if( sv.state == ss_active && sv_ent->s.ed_type == ED_SPAWNED )
2009-11-28 22:00:00 +01:00
SV_ClassifyEdict( ent, ED_SPAWNED );
2009-01-04 22:00:00 +01:00
2007-06-21 22:00:00 +02:00
// set the abs box
2009-01-02 22:00:00 +01:00
svgame.dllFuncs.pfnSetAbsBox( ent );
2007-06-21 22:00:00 +02:00
2007-08-17 22:00:00 +02:00
// link to PVS leafs
2008-01-17 22:00:00 +01:00
sv_ent->num_clusters = 0;
2009-11-10 22:00:00 +01:00
sv_ent->areanum = 0;
sv_ent->areanum2 = 0;
2007-06-21 22:00:00 +02:00
2008-01-17 22:00:00 +01:00
// get all leafs, including solids
2009-11-02 22:00:00 +01:00
num_leafs = CM_BoxLeafnums( ent->v.absmin, ent->v.absmax, leafs, MAX_TOTAL_ENT_LEAFS, &lastleaf );
2007-06-21 22:00:00 +02:00
2008-01-17 22:00:00 +01:00
// 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++ )
2007-06-21 22:00:00 +02:00
{
2009-11-10 22:00:00 +01:00
clusters[i] = CM_LeafCluster( leafs[i] );
2009-11-03 22:00:00 +01:00
area = CM_LeafArea( leafs[i] );
2009-11-10 22:00:00 +01:00
if( area )
2008-01-17 22:00:00 +01:00
{
// doors may legally straggle two areas,
2007-06-21 22:00:00 +02:00
// but nothing should evern need more than that
2009-11-10 22:00:00 +01:00
if( sv_ent->areanum && sv_ent->areanum != area )
2007-06-21 22:00:00 +02:00
{
2009-11-10 22:00:00 +01:00
if( sv_ent->areanum2 && sv_ent->areanum2 != area && sv.state == ss_loading )
2008-01-17 22:00:00 +01:00
{
2008-12-15 22:00:00 +01:00
float *v = ent->v.absmin;
2009-11-10 22:00:00 +01:00
MsgDev( D_WARN, "SV_LinkEdict: object touching 3 areas at %f %f %f\n", v[0], v[1], v[2] );
2008-01-17 22:00:00 +01:00
}
2008-11-14 22:00:00 +01:00
sv_ent->areanum2 = area;
2007-06-21 22:00:00 +02:00
}
2008-11-14 22:00:00 +01:00
else sv_ent->areanum = area;
2007-06-21 22:00:00 +02:00
}
}
2009-11-10 22:00:00 +01:00
sv_ent->lastcluster = -1;
sv_ent->num_clusters = 0;
2009-07-12 22:00:00 +02:00
for( i = 0; i < num_leafs; i++ )
2007-06-21 22:00:00 +02:00
{
2009-11-10 22:00:00 +01:00
if( clusters[i] == -1 )
continue; // not a visible leaf
for( j = 0; j < i; j++ )
{
if( clusters[j] == clusters[i] )
break;
}
if( j == i )
2009-07-12 22:00:00 +02:00
{
if( sv_ent->num_clusters == MAX_ENT_CLUSTERS )
2009-11-10 22:00:00 +01:00
{
// we missed some leafs, so store the last visible cluster
sv_ent->lastcluster = CM_LeafCluster( lastleaf );
2009-07-12 22:00:00 +02:00
break;
2009-11-10 22:00:00 +01:00
}
sv_ent->clusternums[sv_ent->num_clusters++] = clusters[i];
2007-06-21 22:00:00 +02:00
}
}
2008-12-26 22:00:00 +01:00
ent->pvServerData->linkcount++;
2009-01-14 22:00:00 +01:00
ent->pvServerData->s.ed_flags |= ESF_LINKEDICT; // change edict state on a client too...
2009-11-02 22:00:00 +01:00
sv_ent->linked = true;
// ignore not solid bodies
2009-10-28 22:00:00 +01:00
if( ent->v.solid == SOLID_NOT )
2007-11-27 22:00:00 +01:00
return;
2007-06-21 22:00:00 +02:00
2008-11-14 22:00:00 +01:00
// find the first node that the ent's box crosses
node = sv_areanodes;
2009-11-02 22:00:00 +01:00
2008-01-17 22:00:00 +01:00
while( 1 )
2007-06-21 22:00:00 +02:00
{
2008-07-30 22:00:00 +02:00
if( node->axis == -1 ) break;
2008-12-15 22:00:00 +01:00
if( ent->v.absmin[node->axis] > node->dist )
2007-06-21 22:00:00 +02:00
node = node->children[0];
2008-12-15 22:00:00 +01:00
else if( ent->v.absmax[node->axis] < node->dist )
2007-06-21 22:00:00 +02:00
node = node->children[1];
2007-08-17 22:00:00 +02:00
else break; // crosses the node
2007-06-21 22:00:00 +02:00
}
2008-11-14 22:00:00 +01:00
// link it in
2008-12-15 22:00:00 +01:00
if( ent->v.solid == SOLID_TRIGGER )
2009-11-02 22:00:00 +01:00
InsertLinkBefore( &sv_ent->area, &node->trigger_edicts, NUM_FOR_EDICT( ent ));
else InsertLinkBefore (&sv_ent->area, &node->solid_edicts, NUM_FOR_EDICT( ent ));
if( touch_triggers ) SV_TouchLinks( ent, sv_areanodes );
2007-06-21 22:00:00 +02:00
}
2008-01-17 22:00:00 +01:00
/*
============================================================================
AREA QUERY
2007-06-21 22:00:00 +02:00
2008-01-17 22:00:00 +01:00
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.
============================================================================
*/
2007-06-21 22:00:00 +02:00
/*
====================
SV_AreaEdicts_r
====================
*/
2008-11-14 22:00:00 +01:00
void SV_AreaEdicts_r( areanode_t *node, area_t *ap )
2007-06-21 22:00:00 +02:00
{
2008-11-14 22:00:00 +01:00
link_t *l, *next, *start;
edict_t *check;
int count = 0;
// touch linked edicts
if( ap->type == AREA_SOLID )
start = &node->solid_edicts;
else start = &node->trigger_edicts;
2007-06-21 22:00:00 +02:00
2008-11-14 22:00:00 +01:00
for( l = start->next; l != start; l = next )
2007-06-21 22:00:00 +02:00
{
2008-11-14 22:00:00 +01:00
next = l->next;
check = EDICT_FROM_AREA( l );
2007-06-21 22:00:00 +02:00
2008-12-15 22:00:00 +01:00
if( check->v.solid == SOLID_NOT ) continue; // deactivated
2009-07-12 22:00:00 +02:00
if( !BoundsIntersect( check->v.absmin, check->v.absmax, ap->mins, ap->maxs ))
2007-08-17 22:00:00 +02:00
continue; // not touching
2007-06-21 22:00:00 +02:00
2008-01-17 22:00:00 +01:00
if( ap->count == ap->maxcount )
2007-06-21 22:00:00 +02:00
{
2008-11-14 22:00:00 +01:00
MsgDev( D_WARN, "SV_AreaEdicts: maxcount hit\n" );
2007-06-21 22:00:00 +02:00
return;
}
2008-11-14 22:00:00 +01:00
ap->list[ap->count] = check;
2008-01-17 22:00:00 +01:00
ap->count++;
2007-06-21 22:00:00 +02:00
}
2008-01-17 22:00:00 +01:00
if( node->axis == -1 ) return; // terminal node
2007-06-21 22:00:00 +02:00
// recurse down both sides
2008-11-14 22:00:00 +01:00
if( ap->maxs[node->axis] > node->dist ) SV_AreaEdicts_r( node->children[0], ap );
if( ap->mins[node->axis] < node->dist ) SV_AreaEdicts_r( node->children[1], ap );
2007-06-21 22:00:00 +02:00
}
/*
================
SV_AreaEdicts
================
*/
2008-11-14 22:00:00 +01:00
int SV_AreaEdicts( const vec3_t mins, const vec3_t maxs, edict_t **list, int maxcount, int areatype )
2007-06-21 22:00:00 +02:00
{
2008-01-17 22:00:00 +01:00
area_t ap;
2007-06-21 22:00:00 +02:00
2008-01-17 22:00:00 +01:00
ap.mins = mins;
ap.maxs = maxs;
ap.list = list;
ap.count = 0;
ap.maxcount = maxcount;
2008-11-14 22:00:00 +01:00
ap.type = areatype;
2007-06-21 22:00:00 +02:00
2008-11-14 22:00:00 +01:00
SV_AreaEdicts_r( sv_areanodes, &ap );
2007-06-21 22:00:00 +02:00
2008-01-17 22:00:00 +01:00
return ap.count;
2009-10-28 22:00:00 +01:00
}
/*
2009-11-02 22:00:00 +01:00
==================
SV_ClipMoveToEntity
2009-10-28 22:00:00 +01:00
2009-11-02 22:00:00 +01:00
Handles selection or creation of a clipping hull, and offseting (and
eventually rotation) of the end points
==================
2009-10-28 22:00:00 +01:00
*/
2009-11-23 22:00:00 +01:00
trace_t SV_ClipMoveToEntity( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, uint umask, int flags )
2009-10-28 22:00:00 +01:00
{
2009-11-02 22:00:00 +01:00
trace_t trace;
2009-10-28 22:00:00 +01:00
model_t handle;
float *origin, *angles;
2009-11-02 22:00:00 +01:00
// fill in a default trace
Mem_Set( &trace, 0, sizeof( trace_t ));
2009-10-28 22:00:00 +01:00
2009-11-15 22:00:00 +01:00
// if it doesn't have any brushes of a type we
// are looking for, ignore it
if(!( umask & World_ContentsForEdict( ent )))
{
trace.flFraction = 1.0f;
trace.fInOpen = true;
return trace;
}
2009-10-28 22:00:00 +01:00
// might intersect, so do an exact clip
2009-11-26 22:00:00 +01:00
handle = World_HullForEntity( ent );
2009-10-28 22:00:00 +01:00
2009-11-02 22:00:00 +01:00
if( ent->v.solid == SOLID_BSP )
angles = ent->v.angles;
else angles = vec3_origin; // boxes don't rotate
origin = ent->v.origin;
2009-10-28 22:00:00 +01:00
2009-11-02 22:00:00 +01:00
if( ent == svgame.edicts )
2009-11-03 22:00:00 +01:00
CM_BoxTrace( &trace, start, end, mins, maxs, handle, umask, TR_AABB );
2009-11-23 22:00:00 +01:00
else if( !(flags & FTRACE_SIMPLEBOX) && CM_GetModelType( ent->v.modelindex ) == mod_studio )
{
if( CM_HitboxTrace( &trace, ent, start, end )); // continue tracing bbox if hitbox missing
else CM_TransformedBoxTrace( &trace, start, end, mins, maxs, handle, umask, origin, angles, TR_AABB );
}
2009-11-03 22:00:00 +01:00
else CM_TransformedBoxTrace( &trace, start, end, mins, maxs, handle, umask, origin, angles, TR_AABB );
2009-10-28 22:00:00 +01:00
2009-11-02 22:00:00 +01:00
// did we clip the move?
if( trace.flFraction < 1.0f || trace.fStartSolid )
trace.pHit = ent;
2010-02-02 22:00:00 +01:00
if( !(flags & FTRACE_SIMPLEBOX) && CM_GetModelType( ent->v.modelindex ) == mod_studio )
{
if( VectorIsNull( mins ) && VectorIsNull( maxs ) && trace.iHitgroup == -1 )
{
trace.flFraction = 1.0f;
trace.pHit = NULL; // clear entity when hitbox not intersected
}
}
2009-11-02 22:00:00 +01:00
return trace;
}
2009-10-28 22:00:00 +01:00
2009-11-26 22:00:00 +01:00
static trace_t SV_CombineTraces( trace_t *cliptrace, trace_t *trace, edict_t *touch, bool is_bmodel )
2009-11-23 22:00:00 +01:00
{
if( trace->fAllSolid )
{
cliptrace->fAllSolid = true;
trace->pHit = touch;
}
else if( trace->fStartSolid )
{
if( is_bmodel )
cliptrace->fStartStuck = true;
cliptrace->fStartSolid = true;
trace->pHit = touch;
}
if( trace->flFraction < cliptrace->flFraction )
{
bool oldStart;
// make sure we keep a startsolid from a previous trace
oldStart = cliptrace->fStartSolid;
trace->pHit = touch;
cliptrace = trace;
cliptrace->fStartSolid |= oldStart;
}
return *cliptrace;
}
2009-10-28 22:00:00 +01:00
/*
====================
2009-11-02 22:00:00 +01:00
SV_ClipToLinks
2009-10-28 22:00:00 +01:00
2009-11-02 22:00:00 +01:00
Mins and maxs enclose the entire area swept by the move
2009-10-28 22:00:00 +01:00
====================
*/
2009-11-26 22:00:00 +01:00
static void SV_ClipToLinks( areanode_t *node, moveclip_t *clip )
2009-10-28 22:00:00 +01:00
{
2009-11-02 22:00:00 +01:00
link_t *l, *next;
edict_t *touch;
trace_t trace;
2009-10-28 22:00:00 +01:00
2009-11-02 22:00:00 +01:00
// touch linked edicts
for( l = node->solid_edicts.next; l != &node->solid_edicts; l = next )
{
next = l->next;
2009-10-28 22:00:00 +01:00
2009-11-02 22:00:00 +01:00
touch = EDICT_FROM_AREA( l );
2009-10-28 22:00:00 +01:00
2009-11-02 22:00:00 +01:00
if( touch->v.solid == SOLID_NOT )
continue;
if( touch == clip->passedict )
continue;
if( touch->v.solid == SOLID_TRIGGER )
2010-02-10 22:00:00 +01:00
Host_Error( "trigger in clipping list\n" );
2009-10-28 22:00:00 +01:00
2009-11-16 22:00:00 +01:00
if( clip->type == MOVE_NOMONSTERS && touch->v.solid != SOLID_BSP )
2009-11-02 22:00:00 +01:00
continue;
2009-10-28 22:00:00 +01:00
2009-11-30 22:00:00 +01:00
// don't clip points against points (they can't collide)
if( VectorCompare( touch->v.mins, touch->v.maxs ) && (clip->type != MOVE_MISSILE || !(touch->v.flags & FL_MONSTER)))
continue;
2009-11-23 22:00:00 +01:00
if( clip->type == MOVE_WORLDONLY )
{
// accept only real bsp models with FL_WORLDBRUSH set
if( CM_GetModelType( touch->v.modelindex ) == mod_brush && touch->v.flags & FL_WORLDBRUSH );
else continue;
}
2009-11-02 22:00:00 +01:00
if( !BoundsIntersect( clip->boxmins, clip->boxmaxs, touch->v.absmin, touch->v.absmax ))
2009-10-28 22:00:00 +01:00
continue;
2009-11-02 22:00:00 +01:00
if( clip->passedict && !VectorIsNull( clip->passedict->v.size ) && VectorIsNull( touch->v.size ))
continue; // points never interact
2009-10-28 22:00:00 +01:00
2009-12-03 22:00:00 +01:00
// custom user filter
if( !svgame.dllFuncs.pfnShouldCollide( touch, clip->passedict ))
continue;
2009-11-23 22:00:00 +01:00
if( clip->flags & FTRACE_IGNORE_GLASS && CM_GetModelType( touch->v.modelindex ) == mod_brush )
{
vec3_t point;
// we can ignore brushes with rendermode != kRenderNormal
switch( touch->v.rendermode )
{
case kRenderTransTexture:
case kRenderTransAlpha:
case kRenderTransAdd:
if( touch->v.renderamt < 200 )
continue;
// check for translucent contents
if( VectorIsNull( touch->v.origin ))
VectorAverage( touch->v.absmin, touch->v.absmax, point );
else VectorCopy( touch->v.origin, point );
if( SV_BaseContents( point, NULL ) & BASECONT_TRANSLUCENT )
continue; // glass detected
default: break;
}
}
2009-11-02 22:00:00 +01:00
// might intersect, so do an exact clip
if( clip->trace.fAllSolid ) return;
2009-10-28 22:00:00 +01:00
2009-11-02 22:00:00 +01:00
if( clip->passedict )
{
if( touch->v.owner == clip->passedict )
continue; // don't clip against own missiles
if( clip->passedict->v.owner == touch )
continue; // don't clip against owner
}
2009-10-28 22:00:00 +01:00
2009-11-23 22:00:00 +01:00
if( touch->v.flags & FL_MONSTER )
trace = SV_ClipMoveToEntity( touch, clip->start, clip->mins2, clip->maxs2, clip->end, clip->umask, clip->flags );
else trace = SV_ClipMoveToEntity( touch, clip->start, clip->mins, clip->maxs, clip->end, clip->umask, clip->flags );
clip->trace = SV_CombineTraces( &clip->trace, &trace, touch, touch->v.solid == SOLID_BSP );
2009-11-02 22:00:00 +01:00
}
// recurse down both sides
if( node->axis == -1 ) return;
2009-10-28 22:00:00 +01:00
2009-11-02 22:00:00 +01:00
if( clip->boxmaxs[node->axis] > node->dist )
SV_ClipToLinks( node->children[0], clip );
if( clip->boxmins[node->axis] < node->dist )
SV_ClipToLinks( node->children[1], clip );
}
2009-10-28 22:00:00 +01:00
/*
==================
2009-11-02 22:00:00 +01:00
SV_Move
2009-10-28 22:00:00 +01:00
==================
*/
2009-11-02 22:00:00 +01:00
trace_t SV_Move( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, int type, edict_t *e )
2009-10-28 22:00:00 +01:00
{
2009-11-02 22:00:00 +01:00
moveclip_t clip;
2009-11-23 22:00:00 +01:00
int i;
2009-10-28 22:00:00 +01:00
2009-11-02 22:00:00 +01:00
Mem_Set( &clip, 0, sizeof( moveclip_t ));
2009-10-28 22:00:00 +01:00
clip.start = start;
2009-11-02 22:00:00 +01:00
clip.end = end;
2009-10-28 22:00:00 +01:00
clip.mins = mins;
clip.maxs = maxs;
2009-11-23 22:00:00 +01:00
clip.type = (type & 0xFF);
clip.flags = (type & 0xFF00);
2009-11-02 22:00:00 +01:00
clip.passedict = e;
2009-11-15 22:00:00 +01:00
clip.umask = World_MaskForEdict( e );
// clip to world
2009-11-23 22:00:00 +01:00
clip.trace = SV_ClipMoveToEntity( EDICT_NUM( 0 ), start, mins, maxs, end, clip.umask, 0 );
2009-11-15 22:00:00 +01:00
2009-11-23 22:00:00 +01:00
if( type == MOVE_MISSILE )
{
for( i = 0; i < 3; i++ )
{
clip.mins2[i] = -15;
clip.maxs2[i] = 15;
}
}
else
{
VectorCopy( mins, clip.mins2 );
VectorCopy( maxs, clip.maxs2 );
}
2009-10-28 22:00:00 +01:00
// create the bounding box of the entire move
2009-11-26 22:00:00 +01:00
World_MoveBounds( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs );
2009-10-28 22:00:00 +01:00
2009-11-02 22:00:00 +01:00
// clip to entities
SV_ClipToLinks( sv_areanodes, &clip );
2009-10-28 22:00:00 +01:00
return clip.trace;
}
2009-11-02 22:00:00 +01:00
/*
==================
SV_MoveToss
==================
*/
trace_t SV_MoveToss( edict_t *tossent, edict_t *ignore )
{
float gravity;
vec3_t move, end;
vec3_t original_origin;
vec3_t original_velocity;
vec3_t original_angles;
vec3_t original_avelocity;
trace_t trace;
int i;
VectorCopy( tossent->v.origin, original_origin );
VectorCopy( tossent->v.velocity, original_velocity );
VectorCopy( tossent->v.angles, original_angles );
VectorCopy( tossent->v.avelocity, original_avelocity );
2009-11-26 22:00:00 +01:00
gravity = tossent->v.gravity * svgame.movevars.gravity * 0.05f;
2009-11-02 22:00:00 +01:00
for( i = 0; i < 200; i++ )
{
SV_CheckVelocity( tossent );
tossent->v.velocity[2] -= gravity;
VectorMA( tossent->v.angles, 0.05f, tossent->v.avelocity, tossent->v.angles );
VectorScale( tossent->v.velocity, 0.05f, move );
VectorAdd( tossent->v.origin, move, end );
trace = SV_Move( tossent->v.origin, tossent->v.mins, tossent->v.maxs, end, MOVE_NORMAL, tossent );
VectorCopy( trace.vecEndPos, tossent->v.origin );
if( trace.flFraction < 1.0f ) break;
}
VectorCopy( original_origin, tossent->v.origin );
VectorCopy( original_velocity, tossent->v.velocity );
VectorCopy( original_angles, tossent->v.angles );
VectorCopy( original_avelocity, tossent->v.avelocity );
2009-10-28 22:00:00 +01:00
2009-11-02 22:00:00 +01:00
return trace;
}
2009-10-28 22:00:00 +01:00
/*
=============
SV_PointContents
2009-11-02 22:00:00 +01:00
2009-10-28 22:00:00 +01:00
=============
*/
2009-11-23 22:00:00 +01:00
int SV_BaseContents( const vec3_t p, edict_t *e )
2009-10-28 22:00:00 +01:00
{
model_t handle;
float *angles;
int i, num, contents, c2;
edict_t *touch[MAX_EDICTS];
edict_t *hit;
2009-11-23 22:00:00 +01:00
// sanity check
if( !p ) return 0;
2009-10-28 22:00:00 +01:00
// get base contents from world
2009-11-03 22:00:00 +01:00
contents = CM_PointContents( p, 0 );
2009-10-28 22:00:00 +01:00
// or in contents from all the other entities
num = SV_AreaEdicts( p, p, touch, MAX_EDICTS, AREA_SOLID );
for( i = 0; i < num; i++ )
{
hit = touch[i];
2009-11-23 22:00:00 +01:00
if( hit == e ) continue;
2009-11-16 22:00:00 +01:00
if( hit->v.flags & (FL_CLIENT|FL_FAKECLIENT|FL_MONSTER))
{
// never get contents from alives
if( hit->v.health > 0.0f ) continue;
}
2009-10-28 22:00:00 +01:00
// might intersect, so do an exact clip
2009-11-26 22:00:00 +01:00
handle = World_HullForEntity( hit );
2009-11-02 22:00:00 +01:00
if( hit->v.solid == SOLID_BSP )
angles = hit->v.angles;
else angles = vec3_origin; // boxes don't rotate
2009-11-16 22:00:00 +01:00
c2 = CM_TransformedPointContents( p, handle, hit->v.origin, angles );
2009-11-15 22:00:00 +01:00
c2 |= World_ContentsForEdict( hit ); // user-defined contents
2009-10-28 22:00:00 +01:00
contents |= c2;
}
return contents;
2009-11-02 22:00:00 +01:00
}
int SV_PointContents( const vec3_t p )
{
2009-11-23 22:00:00 +01:00
return World_ConvertContents( SV_BaseContents( p, NULL ));
2009-11-10 22:00:00 +01:00
}
/*
============
SV_TestPlayerPosition
============
*/
2009-11-15 22:00:00 +01:00
edict_t *SV_TestPlayerPosition( const vec3_t origin, edict_t *pass, TraceResult *tr )
2009-11-10 22:00:00 +01:00
{
2009-11-15 22:00:00 +01:00
float *mins, *maxs;
trace_t result;
2009-11-10 22:00:00 +01:00
2009-11-15 22:00:00 +01:00
svgame.pmove->usehull = bound( 0, svgame.pmove->usehull, 3 );
mins = svgame.pmove->player_mins[svgame.pmove->usehull];
maxs = svgame.pmove->player_maxs[svgame.pmove->usehull];
2009-11-10 22:00:00 +01:00
2009-11-15 22:00:00 +01:00
result = SV_Move( origin, mins, maxs, origin, MOVE_NORMAL, pass );
if( tr ) Mem_Copy( tr, &result, sizeof( *tr ));
2009-11-10 22:00:00 +01:00
2009-11-15 22:00:00 +01:00
if(( result.iContents & World_MaskForEdict( pass )) && result.pHit )
return result.pHit;
2009-11-10 22:00:00 +01:00
return NULL;
2007-09-17 22:00:00 +02:00
}