mirror of
https://github.com/FWGS/xash3d-fwgs
synced 2024-11-10 21:09:07 +01:00
5e0a0765ce
The `.editorconfig` file in this repo is configured to trim all trailing whitespace regardless of whether the line is modified. Trims all trailing whitespace in the repository to make the codebase easier to work with in editors that respect `.editorconfig`. `git blame` becomes less useful on these lines but it already isn't very useful. Commands: ``` find . -type f -name '*.h' -exec sed --in-place 's/[[:space:]]\+$//' {} \+ find . -type f -name '*.c' -exec sed --in-place 's/[[:space:]]\+$//' {} \+ ```
736 lines
17 KiB
C
736 lines
17 KiB
C
/*
|
|
pm_trace.c - pmove player trace code
|
|
Copyright (C) 2010 Uncle Mike
|
|
|
|
This program 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.
|
|
|
|
This program 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.
|
|
*/
|
|
|
|
#include "common.h"
|
|
#include "xash3d_mathlib.h"
|
|
#include "mod_local.h"
|
|
#include "pm_local.h"
|
|
#include "pm_movevars.h"
|
|
#include "enginefeatures.h"
|
|
#include "studio.h"
|
|
#include "world.h"
|
|
|
|
#define PM_AllowHitBoxTrace( model, hull ) ( model && model->type == mod_studio && ( FBitSet( model->flags, STUDIO_TRACE_HITBOX ) || hull == 2 ))
|
|
|
|
static mplane_t pm_boxplanes[6];
|
|
static mclipnode_t pm_boxclipnodes[6];
|
|
static hull_t pm_boxhull;
|
|
|
|
// default hullmins
|
|
static const vec3_t pm_hullmins[MAX_MAP_HULLS] =
|
|
{
|
|
{ -16, -16, -36 },
|
|
{ -16, -16, -18 },
|
|
{ 0, 0, 0 },
|
|
{ -32, -32, -32 },
|
|
};
|
|
|
|
// defualt hullmaxs
|
|
static const vec3_t pm_hullmaxs[MAX_MAP_HULLS] =
|
|
{
|
|
{ 16, 16, 36 },
|
|
{ 16, 16, 18 },
|
|
{ 0, 0, 0 },
|
|
{ 32, 32, 32 },
|
|
};
|
|
|
|
void Pmove_Init( void )
|
|
{
|
|
PM_InitBoxHull ();
|
|
|
|
// init default hull sizes
|
|
memcpy( host.player_mins, pm_hullmins, sizeof( pm_hullmins ));
|
|
memcpy( host.player_maxs, pm_hullmaxs, sizeof( pm_hullmaxs ));
|
|
}
|
|
|
|
/*
|
|
===================
|
|
PM_InitBoxHull
|
|
|
|
Set up the planes and clipnodes so that the six floats of a bounding box
|
|
can just be stored out and get a proper hull_t structure.
|
|
===================
|
|
*/
|
|
void PM_InitBoxHull( void )
|
|
{
|
|
int i, side;
|
|
|
|
pm_boxhull.clipnodes = pm_boxclipnodes;
|
|
pm_boxhull.planes = pm_boxplanes;
|
|
pm_boxhull.firstclipnode = 0;
|
|
pm_boxhull.lastclipnode = 5;
|
|
|
|
for( i = 0; i < 6; i++ )
|
|
{
|
|
pm_boxclipnodes[i].planenum = i;
|
|
|
|
side = i & 1;
|
|
|
|
pm_boxclipnodes[i].children[side] = CONTENTS_EMPTY;
|
|
if( i != 5 ) pm_boxclipnodes[i].children[side^1] = i + 1;
|
|
else pm_boxclipnodes[i].children[side^1] = CONTENTS_SOLID;
|
|
|
|
pm_boxplanes[i].type = i>>1;
|
|
pm_boxplanes[i].normal[i>>1] = 1.0f;
|
|
pm_boxplanes[i].signbits = 0;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
===================
|
|
PM_HullForBox
|
|
|
|
To keep everything totally uniform, bounding boxes are turned into small
|
|
BSP trees instead of being compared directly.
|
|
===================
|
|
*/
|
|
hull_t *PM_HullForBox( const vec3_t mins, const vec3_t maxs )
|
|
{
|
|
pm_boxplanes[0].dist = maxs[0];
|
|
pm_boxplanes[1].dist = mins[0];
|
|
pm_boxplanes[2].dist = maxs[1];
|
|
pm_boxplanes[3].dist = mins[1];
|
|
pm_boxplanes[4].dist = maxs[2];
|
|
pm_boxplanes[5].dist = mins[2];
|
|
|
|
return &pm_boxhull;
|
|
}
|
|
|
|
void PM_ConvertTrace( trace_t *out, pmtrace_t *in, edict_t *ent )
|
|
{
|
|
memcpy( out, in, 48 ); // matched
|
|
out->hitgroup = in->hitgroup;
|
|
out->ent = ent;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
PM_HullPointContents
|
|
|
|
==================
|
|
*/
|
|
int PM_HullPointContents( hull_t *hull, int num, const vec3_t p )
|
|
{
|
|
mplane_t *plane;
|
|
|
|
if( !hull || !hull->planes ) // fantom bmodels?
|
|
return CONTENTS_NONE;
|
|
|
|
while( num >= 0 )
|
|
{
|
|
plane = &hull->planes[hull->clipnodes[num].planenum];
|
|
num = hull->clipnodes[num].children[PlaneDiff( p, plane ) < 0];
|
|
}
|
|
return num;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
PM_HullForBsp
|
|
|
|
assume physent is valid
|
|
==================
|
|
*/
|
|
hull_t *PM_HullForBsp( physent_t *pe, playermove_t *pmove, float *offset )
|
|
{
|
|
hull_t *hull;
|
|
|
|
Assert( pe != NULL );
|
|
Assert( pe->model != NULL );
|
|
|
|
switch( pmove->usehull )
|
|
{
|
|
case 1:
|
|
hull = &pe->model->hulls[3];
|
|
break;
|
|
case 2:
|
|
hull = &pe->model->hulls[0];
|
|
break;
|
|
case 3:
|
|
hull = &pe->model->hulls[2];
|
|
break;
|
|
default:
|
|
hull = &pe->model->hulls[1];
|
|
break;
|
|
}
|
|
|
|
Assert( hull != NULL );
|
|
|
|
// calculate an offset value to center the origin
|
|
VectorSubtract( hull->clip_mins, pmove->player_mins[pmove->usehull], offset );
|
|
VectorAdd( offset, pe->origin, offset );
|
|
|
|
return hull;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
PM_HullForStudio
|
|
|
|
generate multiple hulls as hitboxes
|
|
==================
|
|
*/
|
|
hull_t *PM_HullForStudio( physent_t *pe, playermove_t *pmove, int *numhitboxes )
|
|
{
|
|
vec3_t size;
|
|
|
|
VectorSubtract( pmove->player_maxs[pmove->usehull], pmove->player_mins[pmove->usehull], size );
|
|
VectorScale( size, 0.5f, size );
|
|
|
|
return Mod_HullForStudio( pe->studiomodel, pe->frame, pe->sequence, pe->angles, pe->origin, size, pe->controller, pe->blending, numhitboxes, NULL );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
PM_RecursiveHullCheck
|
|
==================
|
|
*/
|
|
qboolean PM_RecursiveHullCheck( hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, pmtrace_t *trace )
|
|
{
|
|
mclipnode_t *node;
|
|
mplane_t *plane;
|
|
float t1, t2;
|
|
float frac, midf;
|
|
int side;
|
|
vec3_t mid;
|
|
loc0:
|
|
// check for empty
|
|
if( num < 0 )
|
|
{
|
|
if( num != CONTENTS_SOLID )
|
|
{
|
|
trace->allsolid = false;
|
|
if( num == CONTENTS_EMPTY )
|
|
trace->inopen = true;
|
|
else trace->inwater = true;
|
|
}
|
|
else trace->startsolid = true;
|
|
return true; // empty
|
|
}
|
|
|
|
if( hull->firstclipnode >= hull->lastclipnode )
|
|
{
|
|
// empty hull?
|
|
trace->allsolid = false;
|
|
trace->inopen = true;
|
|
return true;
|
|
}
|
|
|
|
if( num < hull->firstclipnode || num > hull->lastclipnode )
|
|
Host_Error( "PM_RecursiveHullCheck: bad node number %i\n", num );
|
|
|
|
// find the point distances
|
|
node = hull->clipnodes + num;
|
|
plane = hull->planes + node->planenum;
|
|
|
|
t1 = PlaneDiff( p1, plane );
|
|
t2 = PlaneDiff( p2, plane );
|
|
|
|
if( t1 >= 0.0f && t2 >= 0.0f )
|
|
{
|
|
num = node->children[0];
|
|
goto loc0;
|
|
}
|
|
|
|
if( t1 < 0.0f && t2 < 0.0f )
|
|
{
|
|
num = node->children[1];
|
|
goto loc0;
|
|
}
|
|
|
|
// put the crosspoint DIST_EPSILON pixels on the near side
|
|
side = (t1 < 0.0f);
|
|
|
|
if( side ) frac = ( t1 + DIST_EPSILON ) / ( t1 - t2 );
|
|
else frac = ( t1 - DIST_EPSILON ) / ( t1 - t2 );
|
|
|
|
if( frac < 0.0f ) frac = 0.0f;
|
|
if( frac > 1.0f ) frac = 1.0f;
|
|
|
|
midf = p1f + ( p2f - p1f ) * frac;
|
|
VectorLerp( p1, frac, p2, mid );
|
|
|
|
// move up to the node
|
|
if( !PM_RecursiveHullCheck( hull, node->children[side], p1f, midf, p1, mid, trace ))
|
|
return false;
|
|
|
|
// this recursion can not be optimized because mid would need to be duplicated on a stack
|
|
if( PM_HullPointContents( hull, node->children[side^1], mid ) != CONTENTS_SOLID )
|
|
{
|
|
// go past the node
|
|
return PM_RecursiveHullCheck( hull, node->children[side^1], midf, p2f, mid, p2, trace );
|
|
}
|
|
|
|
// never got out of the solid area
|
|
if( trace->allsolid )
|
|
return false;
|
|
|
|
// the other side of the node is solid, this is the impact point
|
|
if( !side )
|
|
{
|
|
VectorCopy( plane->normal, trace->plane.normal );
|
|
trace->plane.dist = plane->dist;
|
|
}
|
|
else
|
|
{
|
|
VectorNegate( plane->normal, trace->plane.normal );
|
|
trace->plane.dist = -plane->dist;
|
|
}
|
|
|
|
while( PM_HullPointContents( hull, hull->firstclipnode, mid ) == CONTENTS_SOLID )
|
|
{
|
|
// shouldn't really happen, but does occasionally
|
|
frac -= 0.1f;
|
|
|
|
if( frac < 0.0f )
|
|
{
|
|
trace->fraction = midf;
|
|
VectorCopy( mid, trace->endpos );
|
|
Con_Reportf( S_WARN "trace backed up past 0.0\n" );
|
|
return false;
|
|
}
|
|
|
|
midf = p1f + ( p2f - p1f ) * frac;
|
|
VectorLerp( p1, frac, p2, mid );
|
|
}
|
|
|
|
trace->fraction = midf;
|
|
VectorCopy( mid, trace->endpos );
|
|
|
|
return false;
|
|
}
|
|
|
|
pmtrace_t PM_PlayerTraceExt( playermove_t *pmove, vec3_t start, vec3_t end, int flags, int numents, physent_t *ents, int ignore_pe, pfnIgnore pmFilter )
|
|
{
|
|
physent_t *pe;
|
|
matrix4x4 matrix;
|
|
pmtrace_t trace_bbox;
|
|
pmtrace_t trace_hitbox;
|
|
pmtrace_t trace_total;
|
|
vec3_t offset, start_l, end_l;
|
|
vec3_t temp, mins, maxs;
|
|
int i, j, hullcount;
|
|
qboolean rotated, transform_bbox;
|
|
hull_t *hull = NULL;
|
|
|
|
memset( &trace_total, 0, sizeof( trace_total ));
|
|
VectorCopy( end, trace_total.endpos );
|
|
trace_total.fraction = 1.0f;
|
|
trace_total.ent = -1;
|
|
|
|
for( i = 0; i < numents; i++ )
|
|
{
|
|
pe = &ents[i];
|
|
|
|
if( i != 0 && ( flags & PM_WORLD_ONLY ))
|
|
break;
|
|
|
|
// run custom user filter
|
|
if( pmFilter != NULL )
|
|
{
|
|
if( pmFilter( pe ))
|
|
continue;
|
|
}
|
|
else if( ignore_pe != -1 )
|
|
{
|
|
if( i == ignore_pe )
|
|
continue;
|
|
}
|
|
|
|
if( pe->model != NULL && pe->solid == SOLID_NOT && pe->skin != CONTENTS_NONE )
|
|
continue;
|
|
|
|
if(( flags & PM_GLASS_IGNORE ) && pe->rendermode != kRenderNormal )
|
|
continue;
|
|
|
|
if(( flags & PM_CUSTOM_IGNORE ) && pe->solid == SOLID_CUSTOM )
|
|
continue;
|
|
|
|
hullcount = 1;
|
|
|
|
if( pe->solid == SOLID_CUSTOM )
|
|
{
|
|
VectorCopy( pmove->player_mins[pmove->usehull], mins );
|
|
VectorCopy( pmove->player_maxs[pmove->usehull], maxs );
|
|
VectorClear( offset );
|
|
}
|
|
else if( pe->model )
|
|
{
|
|
hull = PM_HullForBsp( pe, pmove, offset );
|
|
}
|
|
else
|
|
{
|
|
if( pe->studiomodel )
|
|
{
|
|
if( FBitSet( flags, PM_STUDIO_IGNORE ))
|
|
continue;
|
|
|
|
if( PM_AllowHitBoxTrace( pe->studiomodel, pmove->usehull ) && !FBitSet( flags, PM_STUDIO_BOX ))
|
|
{
|
|
hull = PM_HullForStudio( pe, pmove, &hullcount );
|
|
VectorClear( offset );
|
|
}
|
|
else
|
|
{
|
|
VectorSubtract( pe->mins, pmove->player_maxs[pmove->usehull], mins );
|
|
VectorSubtract( pe->maxs, pmove->player_mins[pmove->usehull], maxs );
|
|
|
|
hull = PM_HullForBox( mins, maxs );
|
|
VectorCopy( pe->origin, offset );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VectorSubtract( pe->mins, pmove->player_maxs[pmove->usehull], mins );
|
|
VectorSubtract( pe->maxs, pmove->player_mins[pmove->usehull], maxs );
|
|
|
|
hull = PM_HullForBox( mins, maxs );
|
|
VectorCopy( pe->origin, offset );
|
|
}
|
|
|
|
}
|
|
|
|
if( pe->solid == SOLID_BSP && !VectorIsNull( pe->angles ))
|
|
rotated = true;
|
|
else rotated = false;
|
|
|
|
if( FBitSet( host.features, ENGINE_PHYSICS_PUSHER_EXT ))
|
|
{
|
|
if(( check_angles( pe->angles[0] ) || check_angles( pe->angles[2] )) && pmove->usehull != 2 )
|
|
transform_bbox = true;
|
|
else transform_bbox = false;
|
|
}
|
|
else transform_bbox = false;
|
|
|
|
if( rotated )
|
|
{
|
|
if( transform_bbox )
|
|
Matrix4x4_CreateFromEntity( matrix, pe->angles, pe->origin, 1.0f );
|
|
else Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
|
|
|
|
Matrix4x4_VectorITransform( matrix, start, start_l );
|
|
Matrix4x4_VectorITransform( matrix, end, end_l );
|
|
|
|
if( transform_bbox )
|
|
{
|
|
World_TransformAABB( matrix, pmove->player_mins[pmove->usehull], pmove->player_maxs[pmove->usehull], mins, maxs );
|
|
VectorSubtract( hull->clip_mins, mins, offset ); // calc new local offset
|
|
|
|
for( j = 0; j < 3; j++ )
|
|
{
|
|
if( start_l[j] >= 0.0f )
|
|
start_l[j] -= offset[j];
|
|
else start_l[j] += offset[j];
|
|
if( end_l[j] >= 0.0f )
|
|
end_l[j] -= offset[j];
|
|
else end_l[j] += offset[j];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VectorSubtract( start, offset, start_l );
|
|
VectorSubtract( end, offset, end_l );
|
|
}
|
|
|
|
memset( &trace_bbox, 0, sizeof( trace_bbox ));
|
|
VectorCopy( end, trace_bbox.endpos );
|
|
trace_bbox.allsolid = true;
|
|
trace_bbox.fraction = 1.0f;
|
|
|
|
if( hullcount < 1 )
|
|
{
|
|
// g-cont. probably this never happens
|
|
trace_bbox.allsolid = false;
|
|
}
|
|
else if( pe->solid == SOLID_CUSTOM )
|
|
{
|
|
// run custom sweep callback
|
|
if( pmove->server || Host_IsLocalClient( ))
|
|
SV_ClipPMoveToEntity( pe, start, mins, maxs, end, &trace_bbox );
|
|
#if !XASH_DEDICATED
|
|
else CL_ClipPMoveToEntity( pe, start, mins, maxs, end, &trace_bbox );
|
|
#endif
|
|
}
|
|
else if( hullcount == 1 )
|
|
{
|
|
PM_RecursiveHullCheck( hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace_bbox );
|
|
}
|
|
else
|
|
{
|
|
int last_hitgroup;
|
|
|
|
for( last_hitgroup = 0, j = 0; j < hullcount; j++ )
|
|
{
|
|
memset( &trace_hitbox, 0, sizeof( trace_hitbox ));
|
|
VectorCopy( end, trace_hitbox.endpos );
|
|
trace_hitbox.allsolid = true;
|
|
trace_hitbox.fraction = 1.0f;
|
|
|
|
PM_RecursiveHullCheck( &hull[j], hull[j].firstclipnode, 0, 1, start_l, end_l, &trace_hitbox );
|
|
|
|
if( j == 0 || trace_hitbox.allsolid || trace_hitbox.startsolid || trace_hitbox.fraction < trace_bbox.fraction )
|
|
{
|
|
if( trace_bbox.startsolid )
|
|
{
|
|
trace_bbox = trace_hitbox;
|
|
trace_bbox.startsolid = true;
|
|
}
|
|
else trace_bbox = trace_hitbox;
|
|
|
|
last_hitgroup = j;
|
|
}
|
|
}
|
|
|
|
trace_bbox.hitgroup = Mod_HitgroupForStudioHull( last_hitgroup );
|
|
}
|
|
|
|
if( trace_bbox.allsolid )
|
|
trace_bbox.startsolid = true;
|
|
|
|
if( trace_bbox.startsolid )
|
|
trace_bbox.fraction = 0.0f;
|
|
|
|
if( !trace_bbox.startsolid )
|
|
{
|
|
VectorLerp( start, trace_bbox.fraction, end, trace_bbox.endpos );
|
|
|
|
if( rotated )
|
|
{
|
|
VectorCopy( trace_bbox.plane.normal, temp );
|
|
Matrix4x4_TransformPositivePlane( matrix, temp, trace_bbox.plane.dist, trace_bbox.plane.normal, &trace_bbox.plane.dist );
|
|
}
|
|
else
|
|
{
|
|
trace_bbox.plane.dist = DotProduct( trace_bbox.endpos, trace_bbox.plane.normal );
|
|
}
|
|
}
|
|
|
|
if( trace_bbox.fraction < trace_total.fraction )
|
|
{
|
|
trace_total = trace_bbox;
|
|
trace_total.ent = i;
|
|
}
|
|
}
|
|
|
|
return trace_total;
|
|
}
|
|
|
|
int PM_TestPlayerPosition( playermove_t *pmove, vec3_t pos, pmtrace_t *ptrace, pfnIgnore pmFilter )
|
|
{
|
|
int i, j, hullcount;
|
|
vec3_t pos_l, offset;
|
|
hull_t *hull = NULL;
|
|
vec3_t mins, maxs;
|
|
pmtrace_t trace;
|
|
physent_t *pe;
|
|
|
|
trace = PM_PlayerTraceExt( pmove, pmove->origin, pmove->origin, 0, pmove->numphysent, pmove->physents, -1, pmFilter );
|
|
if( ptrace ) *ptrace = trace;
|
|
|
|
for( i = 0; i < pmove->numphysent; i++ )
|
|
{
|
|
pe = &pmove->physents[i];
|
|
|
|
// run custom user filter
|
|
if( pmFilter != NULL )
|
|
{
|
|
if( pmFilter( pe ))
|
|
continue;
|
|
}
|
|
|
|
if( pe->model != NULL && pe->solid == SOLID_NOT && pe->skin != CONTENTS_NONE )
|
|
continue;
|
|
|
|
hullcount = 1;
|
|
|
|
if( pe->solid == SOLID_CUSTOM )
|
|
{
|
|
VectorCopy( pmove->player_mins[pmove->usehull], mins );
|
|
VectorCopy( pmove->player_maxs[pmove->usehull], maxs );
|
|
VectorClear( offset );
|
|
}
|
|
else if( pe->model )
|
|
{
|
|
hull = PM_HullForBsp( pe, pmove, offset );
|
|
}
|
|
else if( PM_AllowHitBoxTrace( pe->studiomodel, pmove->usehull ))
|
|
{
|
|
hull = PM_HullForStudio( pe, pmove, &hullcount );
|
|
VectorClear( offset );
|
|
}
|
|
else
|
|
{
|
|
VectorSubtract( pe->mins, pmove->player_maxs[pmove->usehull], mins );
|
|
VectorSubtract( pe->maxs, pmove->player_mins[pmove->usehull], maxs );
|
|
|
|
hull = PM_HullForBox( mins, maxs );
|
|
VectorCopy( pe->origin, offset );
|
|
}
|
|
|
|
// CM_TransformedPointContents :-)
|
|
if( pe->solid == SOLID_BSP && !VectorIsNull( pe->angles ))
|
|
{
|
|
qboolean transform_bbox = false;
|
|
matrix4x4 matrix;
|
|
|
|
if( FBitSet( host.features, ENGINE_PHYSICS_PUSHER_EXT ))
|
|
{
|
|
if(( check_angles( pe->angles[0] ) || check_angles( pe->angles[2] )) && pmove->usehull != 2 )
|
|
transform_bbox = true;
|
|
}
|
|
|
|
if( transform_bbox )
|
|
Matrix4x4_CreateFromEntity( matrix, pe->angles, pe->origin, 1.0f );
|
|
else Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
|
|
|
|
Matrix4x4_VectorITransform( matrix, pos, pos_l );
|
|
|
|
if( transform_bbox )
|
|
{
|
|
World_TransformAABB( matrix, pmove->player_mins[pmove->usehull], pmove->player_maxs[pmove->usehull], mins, maxs );
|
|
VectorSubtract( hull->clip_mins, mins, offset ); // calc new local offset
|
|
|
|
for( j = 0; j < 3; j++ )
|
|
{
|
|
if( pos_l[j] >= 0.0f )
|
|
pos_l[j] -= offset[j];
|
|
else pos_l[j] += offset[j];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// offset the test point appropriately for this hull.
|
|
VectorSubtract( pos, offset, pos_l );
|
|
}
|
|
|
|
if( pe->solid == SOLID_CUSTOM )
|
|
{
|
|
pmtrace_t trace;
|
|
|
|
memset( &trace, 0, sizeof( trace ));
|
|
VectorCopy( pos, trace.endpos );
|
|
trace.allsolid = true;
|
|
trace.fraction = 1.0f;
|
|
|
|
// run custom sweep callback
|
|
if( pmove->server || Host_IsLocalClient( ))
|
|
SV_ClipPMoveToEntity( pe, pos, mins, maxs, pos, &trace );
|
|
#if !XASH_DEDICATED
|
|
else CL_ClipPMoveToEntity( pe, pos, mins, maxs, pos, &trace );
|
|
#endif
|
|
|
|
// if we inside the custom hull
|
|
if( trace.allsolid )
|
|
return i;
|
|
}
|
|
else if( hullcount == 1 )
|
|
{
|
|
if( PM_HullPointContents( hull, hull->firstclipnode, pos_l ) == CONTENTS_SOLID )
|
|
return i;
|
|
}
|
|
else
|
|
{
|
|
for( j = 0; j < hullcount; j++ )
|
|
{
|
|
if( PM_HullPointContents( &hull[j], hull[j].firstclipnode, pos_l ) == CONTENTS_SOLID )
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1; // didn't hit anything
|
|
}
|
|
|
|
/*
|
|
=============
|
|
PM_TruePointContents
|
|
|
|
=============
|
|
*/
|
|
int PM_TruePointContents( playermove_t *pmove, const vec3_t p )
|
|
{
|
|
hull_t *hull = &pmove->physents[0].model->hulls[0];
|
|
|
|
if( hull )
|
|
{
|
|
return PM_HullPointContents( hull, hull->firstclipnode, p );
|
|
}
|
|
else
|
|
{
|
|
return CONTENTS_EMPTY;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=============
|
|
PM_PointContents
|
|
|
|
=============
|
|
*/
|
|
int PM_PointContents( playermove_t *pmove, const vec3_t p )
|
|
{
|
|
int i, contents;
|
|
hull_t *hull;
|
|
vec3_t test;
|
|
physent_t *pe;
|
|
|
|
// sanity check
|
|
if( !p || !pmove->physents[0].model )
|
|
return CONTENTS_NONE;
|
|
|
|
// get base contents from world
|
|
contents = PM_HullPointContents( &pmove->physents[0].model->hulls[0], 0, p );
|
|
|
|
for( i = 1; i < pmove->numphysent; i++ )
|
|
{
|
|
pe = &pmove->physents[i];
|
|
|
|
if( pe->solid != SOLID_NOT ) // disabled ?
|
|
continue;
|
|
|
|
// only brushes can have special contents
|
|
if( !pe->model ) continue;
|
|
|
|
// check water brushes accuracy
|
|
hull = &pe->model->hulls[0];
|
|
|
|
if( FBitSet( pe->model->flags, MODEL_HAS_ORIGIN ) && !VectorIsNull( pe->angles ))
|
|
{
|
|
matrix4x4 matrix;
|
|
|
|
Matrix4x4_CreateFromEntity( matrix, pe->angles, pe->origin, 1.0f );
|
|
Matrix4x4_VectorITransform( matrix, p, test );
|
|
}
|
|
else
|
|
{
|
|
// offset the test point appropriately for this hull.
|
|
VectorSubtract( p, pe->origin, test );
|
|
}
|
|
|
|
// test hull for intersection with this model
|
|
if( PM_HullPointContents( hull, hull->firstclipnode, test ) == CONTENTS_EMPTY )
|
|
continue;
|
|
|
|
// compare contents ranking
|
|
if( RankForContents( pe->skin ) > RankForContents( contents ))
|
|
contents = pe->skin; // new content has more priority
|
|
}
|
|
|
|
return contents;
|
|
}
|