jediacademy/code/game/g_navnew.cpp
2013-04-04 17:35:38 -05:00

227 lines
6.3 KiB
C++

// leave this line at the top for all g_xxxx.cpp files...
#include "g_headers.h"
extern qboolean G_EntIsUnlockedDoor( int entityNum );
extern qboolean FlyingCreature( gentity_t *ent );
#define MIN_DOOR_BLOCK_DIST 16
#define MIN_DOOR_BLOCK_DIST_SQR ( MIN_DOOR_BLOCK_DIST * MIN_DOOR_BLOCK_DIST )
/*
-------------------------
NAV_HitNavGoal
-------------------------
*/
qboolean NAV_HitNavGoal( vec3_t point, vec3_t mins, vec3_t maxs, vec3_t dest, int radius, qboolean flying )
{
vec3_t dmins, dmaxs, pmins, pmaxs;
if ( radius )
{
radius;
//NOTE: This needs to do a DistanceSquared on navgoals that had
// a radius manually set! We can't do the smaller navgoals against
// walls to get around this because player-sized traces to them
// from angles will not work... - MCG
if ( !flying )
{//Allow for a little z difference
vec3_t diff;
VectorSubtract( point, dest, diff );
if ( fabs(diff[2]) <= 24 )
{
diff[2] = 0;
}
return ( VectorLengthSquared( diff ) <= (radius*radius) );
}
else
{//must hit exactly
return ( DistanceSquared(dest, point) <= (radius*radius) );
}
//There is probably a better way to do this, either by preserving the original
// mins and maxs of the navgoal and doing this check ONLY if the radius
// is non-zero (like the original implementation) or some boolean to
// tell us to do this check rather than the fake bbox overlap check...
}
else
{
//Construct a dummy bounding box from our radius value
VectorSet( dmins, -radius, -radius, -radius );
VectorSet( dmaxs, radius, radius, radius );
//Translate it
VectorAdd( dmins, dest, dmins );
VectorAdd( dmaxs, dest, dmaxs );
//Translate the starting box
VectorAdd( point, mins, pmins );
VectorAdd( point, maxs, pmaxs );
//See if they overlap
return G_BoundsOverlap( pmins, pmaxs, dmins, dmaxs );
}
}
/*
-------------------------
NAV_CheckAhead
-------------------------
*/
qboolean NAV_CheckAhead( gentity_t *self, vec3_t end, trace_t &trace, int clipmask )
{
vec3_t mins;
//Offset the step height
VectorSet( mins, self->mins[0], self->mins[1], self->mins[2] + STEPSIZE );
gi.trace( &trace, self->currentOrigin, mins, self->maxs, end, self->s.number, clipmask );
if ( trace.startsolid&&(trace.contents&CONTENTS_BOTCLIP) )
{//started inside do not enter, so ignore them
clipmask &= ~CONTENTS_BOTCLIP;
gi.trace( &trace, self->currentOrigin, mins, self->maxs, end, self->s.number, clipmask );
}
//Do a simple check
if ( ( trace.allsolid == qfalse ) && ( trace.startsolid == qfalse ) && ( trace.fraction == 1.0f ) )
return qtrue;
//See if we're too far above
if ( fabs( self->currentOrigin[2] - end[2] ) > 48 )
return qfalse;
//This is a work around
float radius = ( self->maxs[0] > self->maxs[1] ) ? self->maxs[0] : self->maxs[1];
float dist = Distance( self->currentOrigin, end );
float tFrac = 1.0f - ( radius / dist );
if ( trace.fraction >= tFrac )
return qtrue;
//Do a special check for doors
if ( trace.entityNum < ENTITYNUM_WORLD )
{
gentity_t *blocker = &g_entities[trace.entityNum];
if VALIDSTRING( blocker->classname )
{
if ( G_EntIsUnlockedDoor( blocker->s.number ) )
//if ( Q_stricmp( blocker->classname, "func_door" ) == 0 )
{
//We're too close, try and avoid the door (most likely stuck on a lip)
if ( DistanceSquared( self->currentOrigin, trace.endpos ) < MIN_DOOR_BLOCK_DIST_SQR )
return qfalse;
return qtrue;
}
}
}
return qfalse;
}
/*
-------------------------
NPC_ClearPathToGoal
-------------------------
*/
qboolean NPC_ClearPathToGoal( vec3_t dir, gentity_t *goal )
{
trace_t trace;
//FIXME: What does do about area portals? THIS IS BROKEN
//if ( gi.inPVS( NPC->currentOrigin, goal->currentOrigin ) == qfalse )
// return qfalse;
//Look ahead and see if we're clear to move to our goal position
if ( NAV_CheckAhead( NPC, goal->currentOrigin, trace, ( NPC->clipmask & ~CONTENTS_BODY )|CONTENTS_BOTCLIP ) )
{
//VectorSubtract( goal->currentOrigin, NPC->currentOrigin, dir );
return qtrue;
}
if (!FlyingCreature(NPC))
{
//See if we're too far above
if ( fabs( NPC->currentOrigin[2] - goal->currentOrigin[2] ) > 48 )
return qfalse;
}
//This is a work around
float radius = ( NPC->maxs[0] > NPC->maxs[1] ) ? NPC->maxs[0] : NPC->maxs[1];
float dist = Distance( NPC->currentOrigin, goal->currentOrigin );
float tFrac = 1.0f - ( radius / dist );
if ( trace.fraction >= tFrac )
return qtrue;
//See if we're looking for a navgoal
if ( goal->svFlags & SVF_NAVGOAL )
{
//Okay, didn't get all the way there, let's see if we got close enough:
if ( NAV_HitNavGoal( trace.endpos, NPC->mins, NPC->maxs, goal->currentOrigin, NPCInfo->goalRadius, FlyingCreature( NPC ) ) )
{
//VectorSubtract(goal->currentOrigin, NPC->currentOrigin, dir);
return qtrue;
}
}
return qfalse;
}
qboolean NAV_DirSafe( gentity_t *self, vec3_t dir, float dist )
{
vec3_t mins, end;
trace_t trace;
VectorMA( self->currentOrigin, dist, dir, end );
//Offset the step height
VectorSet( mins, self->mins[0], self->mins[1], self->mins[2] + STEPSIZE );
gi.trace( &trace, self->currentOrigin, mins, self->maxs, end, self->s.number, CONTENTS_BOTCLIP );
//Do a simple check
if ( ( trace.allsolid == qfalse ) && ( trace.startsolid == qfalse ) && ( trace.fraction == 1.0f ) )
{
return qtrue;
}
return qfalse;
}
qboolean NAV_MoveDirSafe( gentity_t *self, usercmd_t *cmd, float distScale = 1.0f )
{
vec3_t moveDir;
if ( !self || !self->client )
{
return qtrue;
}
if ( !self->client->ps.speed )
{
return qtrue;
}
if ( FlyingCreature( self ) )
{
return qtrue;
}
if ( VectorCompare( self->client->ps.moveDir, vec3_origin ) )
{//no movedir, build from cmd
if ( !cmd->forwardmove && !cmd->rightmove )
{//not moving at all
return qtrue;
}
vec3_t fwd, right, fwdAngs = {0, self->currentAngles[YAW], 0};
AngleVectors( fwdAngs, fwd, right, NULL );
VectorScale( fwd, cmd->forwardmove, fwd );
VectorScale( right, cmd->rightmove, right );
VectorAdd( fwd, right, moveDir );
VectorNormalize( moveDir );
}
else
{
VectorCopy( self->client->ps.moveDir, moveDir );
}
return (NAV_DirSafe( self, moveDir, (self->client->ps.speed/10.0f)*distScale ));
}