codemp/game/NPC_move.c File Reference

#include "b_local.h"
#include "g_nav.h"
#include "anims.h"
#include "../namespace_begin.h"
#include "../namespace_end.h"

Go to the source code of this file.

Functions

void G_Cylinder (vec3_t start, vec3_t end, float radius, vec3_t color)
qboolean G_BoundsOverlap (const vec3_t mins1, const vec3_t maxs1, const vec3_t mins2, const vec3_t maxs2)
int NAV_Steer (gentity_t *self, vec3_t dir, float distance)
int GetTime (int lastTime)
qboolean FlyingCreature (gentity_t *ent)
qboolean PM_InKnockDown (playerState_t *ps)
qboolean NPC_ClearPathToGoal (vec3_t dir, gentity_t *goal)
ID_INLINE qboolean NPC_CheckCombatMove (void)
ID_INLINE qboolean NPC_GetMoveInformation (vec3_t dir, float *distance)
void NAV_GetLastMove (navInfo_t *info)
qboolean NPC_GetMoveDirection (vec3_t out, float *distance)
int NAVNEW_MoveToGoal (gentity_t *self, navInfo_t *info)
qboolean NAVNEW_AvoidCollision (gentity_t *self, gentity_t *goal, navInfo_t *info, qboolean setBlockedInfo, int blockedMovesLimit)
qboolean NPC_GetMoveDirectionAltRoute (vec3_t out, float *distance, qboolean tryStraight)
void G_UcmdMoveForDir (gentity_t *self, usercmd_t *cmd, vec3_t dir)
qboolean NPC_MoveToGoal (qboolean tryStraight)
qboolean NPC_SlideMoveToGoal (void)
void NPC_ApplyRoff (void)

Variables

navInfo_t frameNavInfo


Function Documentation

qboolean FlyingCreature gentity_t ent  ) 
 

Definition at line 46 of file g_nav.c.

References gentity_s::client, gentity_t, playerState_s::gravity, gclient_s::ps, qboolean, qfalse, and qtrue.

Referenced by G_CheckMovingLoopingSounds(), and NPC_ClearPathToGoal().

00047 {
00048         if (ent->client && ent->client->ps.gravity <= 0)
00049         {
00050                 return qtrue;
00051         }
00052         return qfalse;
00053 }

qboolean G_BoundsOverlap const vec3_t  mins1,
const vec3_t  maxs1,
const vec3_t  mins2,
const vec3_t  maxs2
 

Definition at line 94 of file NPC_goal.c.

References qboolean, qfalse, qtrue, and vec3_t.

Referenced by NAV_HitNavGoal(), NAV_TrueCollision(), and NPC_BSGM_Attack().

00095 {//NOTE: flush up against counts as overlapping
00096         if(mins1[0]>maxs2[0])
00097                 return qfalse;
00098 
00099         if(mins1[1]>maxs2[1])
00100                 return qfalse;
00101 
00102         if(mins1[2]>maxs2[2])
00103                 return qfalse;
00104 
00105         if(maxs1[0]<mins2[0])
00106                 return qfalse;
00107 
00108         if(maxs1[1]<mins2[1])
00109                 return qfalse;
00110 
00111         if(maxs1[2]<mins2[2])
00112                 return qfalse;
00113 
00114         return qtrue;
00115 }

void G_Cylinder vec3_t  start,
vec3_t  end,
float  radius,
vec3_t  color
 

void G_UcmdMoveForDir gentity_t self,
usercmd_t cmd,
vec3_t  dir
 

Definition at line 324 of file NPC_move.c.

References AngleVectors(), gentity_s::client, entityShared_t::currentAngles, DotProduct, floor(), usercmd_s::forwardmove, gentity_t, playerState_s::moveDir, NULL, gclient_s::ps, gentity_s::r, usercmd_s::rightmove, usercmd_t, vec3_t, VectorCopy, and VectorNormalize().

Referenced by NPC_MoveToGoal().

00325 {
00326         vec3_t  forward, right;
00327         float   fDot, rDot;
00328 
00329         AngleVectors( self->r.currentAngles, forward, right, NULL );
00330 
00331         dir[2] = 0;
00332         VectorNormalize( dir );
00333         //NPCs cheat and store this directly because converting movement into a ucmd loses precision
00334         VectorCopy( dir, self->client->ps.moveDir );
00335 
00336         fDot = DotProduct( forward, dir ) * 127.0f;
00337         rDot = DotProduct( right, dir ) * 127.0f;
00338         //Must clamp this because DotProduct is not guaranteed to return a number within -1 to 1, and that would be bad when we're shoving this into a signed byte
00339         if ( fDot > 127.0f )
00340         {
00341                 fDot = 127.0f;
00342         }
00343         if ( fDot < -127.0f )
00344         {
00345                 fDot = -127.0f;
00346         }
00347         if ( rDot > 127.0f )
00348         {
00349                 rDot = 127.0f;
00350         }
00351         if ( rDot < -127.0f )
00352         {
00353                 rDot = -127.0f;
00354         }
00355         cmd->forwardmove = floor(fDot);
00356         cmd->rightmove = floor(rDot);
00357 
00358         /*
00359         vec3_t  wishvel;
00360         for ( int i = 0 ; i < 3 ; i++ ) 
00361         {
00362                 wishvel[i] = forward[i]*cmd->forwardmove + right[i]*cmd->rightmove;
00363         }
00364         VectorNormalize( wishvel );
00365         if ( !VectorCompare( wishvel, dir ) )
00366         {
00367                 Com_Printf( "PRECISION LOSS: %s != %s\n", vtos(wishvel), vtos(dir) );
00368         }
00369         */
00370 }

int GetTime int  lastTime  ) 
 

Referenced by NPC_BSST_Attack(), NPC_MoveToGoal(), and NPC_Think().

void NAV_GetLastMove navInfo_t info  ) 
 

Definition at line 149 of file NPC_move.c.

References frameNavInfo, and navInfo_t.

Referenced by AI_CheckEnemyCollision().

00150 {
00151         *info = frameNavInfo;
00152 }

int NAV_Steer gentity_t self,
vec3_t  dir,
float  distance
 

Definition at line 440 of file g_nav.c.

References AngleVectors(), gentity_s::clipmask, CONTENTS_BOTCLIP, entityShared_t::currentOrigin, EDGE_PATH, trace_t::fraction, G_DrawEdge(), gentity_t, NAV_CheckAhead(), NAVDEBUG_showCollision, NULL, gentity_s::r, vec3_t, VectorCopy, VectorMA, and YAW.

00441 {
00442         vec3_t  right_test, left_test;
00443         vec3_t  deviation;
00444         trace_t tr;
00445         float   right_push;
00446         float   left_push;
00447         float   right_ang       = dir[YAW] + 45;
00448         float   left_ang        = dir[YAW] - 45;
00449 
00450         //Get the steering angles
00451         VectorCopy( dir, deviation );
00452         deviation[YAW] = right_ang;
00453 
00454         AngleVectors( deviation, right_test, NULL, NULL );
00455 
00456         deviation[YAW] = left_ang;
00457 
00458         AngleVectors( deviation, left_test, NULL, NULL );
00459 
00460         //Find the end positions
00461         VectorMA( self->r.currentOrigin, distance, right_test, right_test );
00462         VectorMA( self->r.currentOrigin, distance, left_test,  left_test );
00463 
00464         //Draw for debug purposes
00465         if ( NAVDEBUG_showCollision )
00466         {
00467                 G_DrawEdge( self->r.currentOrigin, right_test, EDGE_PATH );
00468                 G_DrawEdge( self->r.currentOrigin, left_test,  EDGE_PATH );
00469         }
00470 
00471         //Find the right influence
00472         NAV_CheckAhead( self, right_test, &tr, self->clipmask|CONTENTS_BOTCLIP );
00473 
00474         right_push = -45 * ( 1.0f - tr.fraction );
00475 
00476         //Find the left influence
00477         NAV_CheckAhead( self, left_test, &tr, self->clipmask|CONTENTS_BOTCLIP );
00478 
00479         left_push = 45 * ( 1.0f - tr.fraction );
00480 
00481         //Influence the mover to respond to the steering
00482         VectorCopy( dir, deviation );
00483         deviation[YAW] += ( left_push + right_push );
00484 
00485         return deviation[YAW];
00486 }

qboolean NAVNEW_AvoidCollision gentity_t self,
gentity_t goal,
navInfo_t info,
qboolean  setBlockedInfo,
int  blockedMovesLimit
 

Definition at line 442 of file g_navnew.c.

References navInfo_s::blocker, gNPC_t::consecutiveBlockedMoves, CONTENTS_BODY, entityShared_t::currentOrigin, d_patched, navInfo_s::direction, navInfo_s::distance, EDGE_MOVEDIR, trace_t::entityNum, navInfo_s::flags, G_DrawEdge(), g_entities, gentity_t, vmCvar_t::integer, MAX_COLL_AVOID_DIST, NAV_CheckAhead(), NAV_TestForBlocked(), NAVDEBUG_showCollision, navInfo_t, NAVNEW_ResolveEntityCollision(), NIF_COLLISION, gentity_s::NPC, NPC_SetBlocked(), navInfo_s::pathDirection, qboolean, qfalse, qtrue, gentity_s::r, navInfo_s::trace, vec3_t, VectorCopy, and VectorMA.

Referenced by NAVNEW_MoveToGoal(), and NPC_GetMoveDirectionAltRoute().

00443 {
00444         vec3_t  movedir;
00445         vec3_t  movepos;
00446 
00447         //Cap our distance
00448         if ( info->distance > MAX_COLL_AVOID_DIST )
00449         {
00450                 info->distance = MAX_COLL_AVOID_DIST;
00451         }
00452 
00453         //Get an end position
00454         VectorMA( self->r.currentOrigin, info->distance, info->direction, movepos );
00455         VectorCopy( info->direction, movedir );
00456 
00457         //Now test against entities
00458         if ( NAV_CheckAhead( self, movepos, &info->trace, CONTENTS_BODY ) == qfalse )
00459         {
00460                 //Get the blocker
00461                 info->blocker = &g_entities[ info->trace.entityNum ];
00462                 info->flags |= NIF_COLLISION;
00463 
00464                 //Ok to hit our goal entity
00465                 if ( goal == info->blocker )
00466                         return qtrue;
00467 
00468                 if ( setBlockedInfo )
00469                 {
00470                         if ( self->NPC->consecutiveBlockedMoves > blockedMovesLimit  )
00471                         {
00472                                 if ( d_patched.integer )
00473                                 {//use patch-style navigation
00474                                         self->NPC->consecutiveBlockedMoves++;
00475                                 }
00476                                 NPC_SetBlocked( self, info->blocker );
00477                                 return qfalse;
00478                         }
00479                         self->NPC->consecutiveBlockedMoves++;
00480                 }
00481                 //See if we're moving along with them
00482                 //if ( NAVNEW_TrueCollision( self, info->blocker, movedir, info->direction ) == qfalse )
00483                 //      return qtrue;
00484 
00485                 //Test for blocking by standing on goal
00486                 if ( NAV_TestForBlocked( self, goal, info->blocker, info->distance, &info->flags ) == qtrue )
00487                         return qfalse;
00488 
00489                 //If the above function said we're blocked, don't do the extra checks
00490                 /*
00491                 if ( info->flags & NIF_BLOCKED )
00492                         return qtrue;
00493                 */
00494 
00495                 //See if we can get that entity to move out of our way
00496                 if ( NAVNEW_ResolveEntityCollision( self, info->blocker, movedir, info->pathDirection, setBlockedInfo ) == qfalse )
00497                         return qfalse;
00498 
00499                 VectorCopy( movedir, info->direction );
00500                 
00501                 return qtrue;
00502         }
00503         else
00504         {
00505                 if ( setBlockedInfo )
00506                 {
00507                         self->NPC->consecutiveBlockedMoves = 0;
00508                 }
00509         }
00510 
00511         //Our path is clear, just move there
00512         if ( NAVDEBUG_showCollision )
00513         {
00514                 G_DrawEdge( self->r.currentOrigin, movepos, EDGE_MOVEDIR );
00515         }
00516 
00517         return qtrue;
00518 }

int NAVNEW_MoveToGoal gentity_t self,
navInfo_t info
 

NAVNEW_GetWaypoints( self, qtrue ) )

Definition at line 578 of file g_navnew.c.

References gNPC_t::aiFlags, gNPC_t::blockedDest, entityShared_t::currentOrigin, d_altRoutes, d_patched, navInfo_s::direction, navInfo_s::distance, EDGE_PATH, G_DrawEdge(), G_DrawNode(), gentity_t, gNPC_t::goalEntity, vmCvar_t::integer, level, memcpy(), NAV_TestBestNode(), NAVDEBUG_showEnemyPath, navInfo_t, NAVNEW_AvoidCollision(), NAVNEW_TestNodeConnectionBlocked(), NF_CLEAR_PATH, NODE_GOAL, NODE_NAVGOAL, NODE_NONE, NODE_START, gentity_s::noWaypointTime, gentity_s::NPC, NPC_ClearBlocked(), NPCAI_BLOCKED, NPCInfo, NULL, entityState_s::number, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, gNPC_t::shoveCount, level_locals_t::time, trap_Nav_AddFailedEdge(), trap_Nav_AddFailedNode(), trap_Nav_GetBestNodeAltRoute2(), trap_Nav_GetBestPathBetweenEnts(), trap_Nav_GetNodePosition(), trap_Nav_NodesAreNeighbors(), trap_Nav_ShowPath(), vec3_t, VectorCopy, VectorNormalize(), VectorSubtract, gentity_s::waypoint, WAYPOINT_NONE, entityState_s::weapon, and WP_SABER.

Referenced by NPC_GetMoveDirectionAltRoute().

00579 {
00580         int                     bestNode = WAYPOINT_NONE;
00581         qboolean        foundClearPath = qfalse;
00582         vec3_t          origin;
00583         navInfo_t       tempInfo;
00584         qboolean        setBlockedInfo = qtrue;
00585         qboolean        inBestWP, inGoalWP, goalWPFailed = qfalse;
00586         int                     numTries = 0;
00587 
00588         memcpy( &tempInfo, info, sizeof( tempInfo ) );
00589 
00590         //Must have a goal entity to move there
00591         if( self->NPC->goalEntity == NULL )
00592                 return WAYPOINT_NONE;
00593 
00594         if ( self->waypoint == WAYPOINT_NONE && self->noWaypointTime > level.time )
00595         {//didn't have a valid one in about the past second, don't look again just yet
00596                 return WAYPOINT_NONE;
00597         }
00598         if ( self->NPC->goalEntity->waypoint == WAYPOINT_NONE && self->NPC->goalEntity->noWaypointTime > level.time )
00599         {//didn't have a valid one in about the past second, don't look again just yet
00600                 return WAYPOINT_NONE;
00601         }
00602         if ( self->noWaypointTime > level.time &&
00603                 self->NPC->goalEntity->noWaypointTime > level.time )
00604         {//just use current waypoints
00605                 bestNode = trap_Nav_GetBestNodeAltRoute2( self->waypoint, self->NPC->goalEntity->waypoint, bestNode );
00606         }
00607         //FIXME!!!!: this is making them wiggle back and forth between waypoints
00608         else if ( (bestNode = trap_Nav_GetBestPathBetweenEnts( self, self->NPC->goalEntity, NF_CLEAR_PATH )) == NODE_NONE )
00609         {//one of us didn't have a valid waypoint!
00610                 if ( self->waypoint == NODE_NONE )
00611                 {//don't even try to find one again for a bit
00612                         self->noWaypointTime = level.time + Q_irand( 500, 1500 );
00613                 }
00614                 if ( self->NPC->goalEntity->waypoint == NODE_NONE )
00615                 {//don't even try to find one again for a bit
00616                         self->NPC->goalEntity->noWaypointTime = level.time + Q_irand( 500, 1500 );
00617                 }
00618                 return WAYPOINT_NONE;
00619         }
00620         else
00621         {
00622                 if ( self->NPC->goalEntity->noWaypointTime < level.time )
00623                 {
00624                         self->NPC->goalEntity->noWaypointTime = level.time + Q_irand( 500, 1500 );
00625                 }
00626         }
00627 
00628         while( !foundClearPath )
00629         {
00630                 inBestWP = inGoalWP = qfalse;
00631                 /*
00632                 bestNode = trap_Nav_GetBestNodeAltRoute( self->waypoint, self->NPC->goalEntity->waypoint, bestNode );
00633                 */
00634 
00635                 if ( bestNode == WAYPOINT_NONE )
00636                 {
00637                         goto failed;
00638                 }
00639 
00640                 //see if we can get directly to the next node off bestNode en route to goal's node...
00641                 //NOTE: shouldn't be necc. now
00642                 /*
00643                 int oldBestNode = bestNode;
00644                 bestNode = NAV_TestBestNode( self, self->waypoint, bestNode, qtrue );//, self->NPC->goalEntity->waypoint );// 
00645                 //NOTE: Guaranteed to return something
00646                 if ( bestNode != oldBestNode )
00647                 {//we were blocked somehow
00648                         if ( setBlockedInfo )
00649                         {
00650                                 self->NPC->aiFlags |= NPCAI_BLOCKED;
00651                                 trap_Nav_GetNodePosition( oldBestNode, NPCInfo->blockedDest );
00652                         }
00653                 }
00654                 */
00655                 trap_Nav_GetNodePosition( bestNode, origin );
00656                 /*
00657                 if ( !goalWPFailed )
00658                 {//we haven't already tried to go straight to goal or goal's wp
00659                         if ( bestNode == self->NPC->goalEntity->waypoint )
00660                         {//our bestNode is the goal's wp
00661                                 if ( NAV_HitNavGoal( self->r.currentOrigin, self->r.mins, self->r.maxs, origin, trap_Nav_GetNodeRadius( bestNode ), FlyingCreature( self ) ) )
00662                                 {//we're in the goal's wp
00663                                         inGoalWP = qtrue;
00664                                         //we're in the goalEntity's waypoint already
00665                                         //so head for the goalEntity since we know it's clear of architecture
00666                                         //FIXME: this is pretty stupid because the NPCs try to go straight
00667                                         //              towards their goal before then even try macro_nav...
00668                                         VectorCopy( self->NPC->goalEntity->r.currentOrigin, origin );
00669                                 }
00670                         }
00671                 }
00672                 */
00673                 if ( !inGoalWP )
00674                 {//not heading straight for goal
00675                         if ( bestNode == self->waypoint )
00676                         {//we know it's clear or architecture
00677                                 //trap_Nav_GetNodePosition( self->waypoint, origin );
00678                                 /*
00679                                 if ( NAV_HitNavGoal( self->r.currentOrigin, self->r.mins, self->r.maxs, origin, trap_Nav_GetNodeRadius( bestNode ), FlyingCreature( self ) ) )
00680                                 {//we're in the wp we're heading for already
00681                                         inBestWP = qtrue;
00682                                 }
00683                                 */
00684                         }
00685                         else
00686                         {//heading to an edge off our confirmed clear waypoint... make sure it's clear
00687                                 //it it's not, bestNode will fall back to our waypoint
00688                                 int oldBestNode = bestNode;
00689                                 bestNode = NAV_TestBestNode( self, self->waypoint, bestNode, qtrue );
00690                                 if ( bestNode == self->waypoint )
00691                                 {//we fell back to our waypoint, reset the origin
00692                                         self->NPC->aiFlags |= NPCAI_BLOCKED;
00693                                         trap_Nav_GetNodePosition( oldBestNode, NPCInfo->blockedDest );
00694                                         trap_Nav_GetNodePosition( bestNode, origin );
00695                                 }
00696                         }
00697                 }
00698                 //Com_Printf( "goalwp = %d, mywp = %d, node = %d, origin = %s\n", self->NPC->goalEntity->waypoint, self->waypoint, bestNode, vtos(origin) );
00699 
00700                 memcpy( &tempInfo, info, sizeof( tempInfo ) );
00701                 VectorSubtract( origin, self->r.currentOrigin, tempInfo.direction );
00702                 VectorNormalize( tempInfo.direction );
00703 
00704                 //NOTE: One very important thing NAVNEW_AvoidCollision does is
00705                 //              it actually CHANGES the value of "direction" - it changes it to
00706                 //              whatever dir you need to go in to avoid the obstacle...
00707                 foundClearPath = NAVNEW_AvoidCollision( self, self->NPC->goalEntity, &tempInfo, setBlockedInfo, 5 );
00708 
00709                 if ( !foundClearPath )
00710                 {//blocked by an ent
00711                         if ( inGoalWP )
00712                         {//we were heading straight for the goal, head for the goal's wp instead
00713                                 trap_Nav_GetNodePosition( bestNode, origin );
00714                                 foundClearPath = NAVNEW_AvoidCollision( self, self->NPC->goalEntity, &tempInfo, setBlockedInfo, 5 );
00715                         }
00716                 }
00717 
00718                 if ( foundClearPath )
00719                 {//clear!
00720                         //If we got set to blocked, clear it
00721                         NPC_ClearBlocked( self );
00722                         //Take the dir
00723                         memcpy( info, &tempInfo, sizeof( *info ) );
00724                         if ( self->s.weapon == WP_SABER )
00725                         {//jedi
00726                                 if ( info->direction[2] * info->distance > 64 )
00727                                 {
00728                                         self->NPC->aiFlags |= NPCAI_BLOCKED;
00729                                         VectorCopy( origin, NPCInfo->blockedDest );
00730                                         goto failed;
00731                                 }
00732                         }
00733                 }
00734                 else
00735                 {//blocked by ent!
00736                         if ( setBlockedInfo )
00737                         {
00738                                 self->NPC->aiFlags |= NPCAI_BLOCKED;
00739                                 trap_Nav_GetNodePosition( bestNode, NPCInfo->blockedDest );
00740                         }
00741                         //Only set blocked info first time
00742                         setBlockedInfo = qfalse;
00743 
00744                         if ( inGoalWP )
00745                         {//we headed for our goal and failed and our goal's WP and failed
00746                                 if ( self->waypoint == self->NPC->goalEntity->waypoint )
00747                                 {//our waypoint is our goal's waypoint, nothing we can do
00748                                         //remember that this node is blocked
00749                                         trap_Nav_AddFailedNode( self, self->waypoint );
00750                                         goto failed;
00751                                 }
00752                                 else
00753                                 {//try going for our waypoint this time
00754                                         goalWPFailed = qtrue;
00755                                         inGoalWP = qfalse;
00756                                 }
00757                         }
00758                         else if ( bestNode != self->waypoint )
00759                         {//we headed toward our next waypoint (instead of our waypoint) and failed
00760                                 if ( d_altRoutes.integer )
00761                                 {//mark this edge failed and try our waypoint
00762                                         //NOTE: don't assume there is something blocking the direct path
00763                                         //                      between my waypoint and the bestNode... I could be off
00764                                         //                      that path because of collision avoidance...
00765                                         if ( d_patched.integer &&//use patch-style navigation
00766                                                 ( !trap_Nav_NodesAreNeighbors( self->waypoint, bestNode )
00767                                                 || NAVNEW_TestNodeConnectionBlocked( self->waypoint, bestNode, self, self->NPC->goalEntity->s.number, qfalse, qtrue ) ) )
00768                                         {//the direct path between these 2 nodes is blocked by an ent
00769                                                 trap_Nav_AddFailedEdge( self->s.number, self->waypoint, bestNode );
00770                                         }
00771                                         bestNode = self->waypoint;
00772                                 }
00773                                 else
00774                                 {
00775                                         //we should stop
00776                                         goto failed;
00777                                 }
00778                         }
00779                         else 
00780                         {//we headed for *our* waypoint and couldn't get to it
00781                                 if ( d_altRoutes.integer )
00782                                 {
00783                                         //remember that this node is blocked
00784                                         trap_Nav_AddFailedNode( self, self->waypoint );
00785                                         //Now we should get our waypoints again
00786                                         //FIXME: cache the trace-data for subsequent calls as only the route info would have changed
00787                                         //if ( (bestNode = trap_Nav_GetBestPathBetweenEnts( self, self->NPC->goalEntity, NF_CLEAR_PATH )) == NODE_NONE )//!NAVNEW_GetWaypoints( self, qfalse ) )
00788                                         {//one of our waypoints is WAYPOINT_NONE now
00789                                                 goto failed;
00790                                         }
00791                                 }
00792                                 else
00793                                 {
00794                                         //we should stop
00795                                         goto failed;
00796                                 }
00797                         }
00798 
00799                         if ( ++numTries >= 10 )
00800                         {
00801                                 goto failed;
00802                         }
00803                 }
00804         }
00805 
00806 //finish:
00807         //Draw any debug info, if requested
00808         if ( NAVDEBUG_showEnemyPath )
00809         {
00810                 vec3_t  dest, start;
00811 
00812                 //Get the positions
00813                 trap_Nav_GetNodePosition( self->NPC->goalEntity->waypoint, dest );
00814                 trap_Nav_GetNodePosition( bestNode, start );
00815 
00816                 //Draw the route
00817                 G_DrawNode( start, NODE_START );
00818                 if ( bestNode != self->waypoint )
00819                 {
00820                         vec3_t  wpPos;
00821                         trap_Nav_GetNodePosition( self->waypoint, wpPos );
00822                         G_DrawNode( wpPos, NODE_NAVGOAL );
00823                 }
00824                 G_DrawNode( dest, NODE_GOAL );
00825                 G_DrawEdge( dest, self->NPC->goalEntity->r.currentOrigin, EDGE_PATH );
00826                 G_DrawNode( self->NPC->goalEntity->r.currentOrigin, NODE_GOAL );
00827                 trap_Nav_ShowPath( bestNode, self->NPC->goalEntity->waypoint );
00828         }
00829 
00830         self->NPC->shoveCount = 0;
00831 
00832         //let me keep this waypoint for a while
00833         if ( self->noWaypointTime < level.time )
00834         {
00835                 self->noWaypointTime = level.time + Q_irand( 500, 1500 );
00836         }
00837         return bestNode;
00838 
00839 failed:
00840         //FIXME: What we should really do here is have a list of the goal's and our
00841         //              closest clearpath waypoints, ranked.  If the first set fails, try the rest
00842         //              until there are no alternatives.
00843 
00844         trap_Nav_GetNodePosition( self->waypoint, origin );
00845 
00846         //do this to avoid ping-ponging?
00847         return WAYPOINT_NONE;
00848         /*
00849         //this was causing ping-ponging
00850         if ( DistanceSquared( origin, self->r.currentOrigin ) < 16 )//woo, magic number
00851         {//We're right up on our waypoint, so that won't help, return none
00852                 //Or maybe find the nextbest here?
00853                 return WAYPOINT_NONE;
00854         }
00855         else
00856         {//Try going to our waypoint
00857                 bestNode = self->waypoint;
00858 
00859                 VectorSubtract( origin, self->r.currentOrigin, info.direction );
00860                 VectorNormalize( info.direction );
00861         }
00862         
00863         goto finish;
00864         */
00865 }

void NPC_ApplyRoff void   ) 
 

Definition at line 497 of file NPC_move.c.

References BG_PlayerStateToEntityState(), gentity_s::client, NPC, gclient_s::ps, qfalse, gentity_s::s, and trap_LinkEntity().

Referenced by NPC_ExecuteBState(), and NPC_Think().

00498 {
00499         BG_PlayerStateToEntityState( &NPC->client->ps, &NPC->s, qfalse );
00500         //VectorCopy ( NPC->r.currentOrigin, NPC->lastOrigin );
00501         //rwwFIXMEFIXME: Any significance to this?
00502 
00503         // use the precise origin for linking
00504         trap_LinkEntity(NPC);
00505 }

ID_INLINE qboolean NPC_CheckCombatMove void   ) 
 

Definition at line 78 of file NPC_move.c.

References gNPC_t::combatMove, gentity_s::enemy, gNPC_t::goalEntity, NPC, NPCInfo, qboolean, qfalse, qtrue, and gNPC_t::watchTarget.

Referenced by NPC_MoveToGoal().

00079 {
00080         //return NPCInfo->combatMove;
00081         if ( ( NPCInfo->goalEntity && NPC->enemy && NPCInfo->goalEntity == NPC->enemy ) || ( NPCInfo->combatMove ) )
00082         {
00083                 return qtrue;
00084         }
00085 
00086         if ( NPCInfo->goalEntity && NPCInfo->watchTarget )
00087         {
00088                 if ( NPCInfo->goalEntity != NPCInfo->watchTarget )
00089                 {
00090                         return qtrue;
00091                 }
00092         }
00093 
00094         return qfalse;
00095 }

qboolean NPC_ClearPathToGoal vec3_t  dir,
gentity_t goal
 

Definition at line 27 of file NPC_move.c.

References gentity_s::clipmask, CONTENTS_BODY, CONTENTS_BOTCLIP, entityShared_t::currentOrigin, trace_t::endpos, fabs(), FL_NAVGOAL, gentity_s::flags, FlyingCreature(), trace_t::fraction, gentity_t, gNPC_t::goalRadius, entityShared_t::maxs, entityShared_t::mins, NAV_CheckAhead(), NAV_HitNavGoal(), NPC, NPCInfo, qboolean, qfalse, qtrue, gentity_s::r, and vec3_t.

Referenced by NPC_GetMoveDirection(), and NPC_GetMoveDirectionAltRoute().

00028 {
00029         trace_t trace;
00030         float radius, dist, tFrac;
00031 
00032         //FIXME: What does do about area portals?  THIS IS BROKEN
00033         //if ( gi.inPVS( NPC->r.currentOrigin, goal->r.currentOrigin ) == qfalse )
00034         //      return qfalse;
00035 
00036         //Look ahead and see if we're clear to move to our goal position
00037         if ( NAV_CheckAhead( NPC, goal->r.currentOrigin, &trace, ( NPC->clipmask & ~CONTENTS_BODY )|CONTENTS_BOTCLIP ) )
00038         {
00039                 //VectorSubtract( goal->r.currentOrigin, NPC->r.currentOrigin, dir );
00040                 return qtrue;
00041         }
00042 
00043         if (!FlyingCreature(NPC))
00044         {
00045                 //See if we're too far above
00046                 if ( fabs( NPC->r.currentOrigin[2] - goal->r.currentOrigin[2] ) > 48 )
00047                         return qfalse;
00048         }
00049 
00050         //This is a work around
00051         radius = ( NPC->r.maxs[0] > NPC->r.maxs[1] ) ? NPC->r.maxs[0] : NPC->r.maxs[1];
00052         dist = Distance( NPC->r.currentOrigin, goal->r.currentOrigin );
00053         tFrac = 1.0f - ( radius / dist );
00054 
00055         if ( trace.fraction >= tFrac )
00056                 return qtrue;
00057 
00058         //See if we're looking for a navgoal
00059         if ( goal->flags & FL_NAVGOAL )
00060         {
00061                 //Okay, didn't get all the way there, let's see if we got close enough:
00062                 if ( NAV_HitNavGoal( trace.endpos, NPC->r.mins, NPC->r.maxs, goal->r.currentOrigin, NPCInfo->goalRadius, FlyingCreature( NPC ) ) )
00063                 {
00064                         //VectorSubtract(goal->r.currentOrigin, NPC->r.currentOrigin, dir);
00065                         return qtrue;
00066                 }
00067         }
00068 
00069         return qfalse;
00070 }

qboolean NPC_GetMoveDirection vec3_t  out,
float *  distance
 

Definition at line 160 of file NPC_move.c.

References AngleNormalize360(), CONTENTS_LADDER, gNPC_t::desiredYaw, navInfo_s::direction, navInfo_s::distance, navInfo_s::flags, frameNavInfo, gNPC_t::goalEntity, memset(), NAV_AvoidCollision(), NAV_MoveToGoal(), NIF_MACRO_NAV, NPC, NPC_ClearPathToGoal(), NPC_GetMoveInformation(), NPCInfo, navInfo_s::pathDirection, qboolean, qfalse, qtrue, vec3_t, vectoangles(), VectorCopy, gentity_s::watertype, WAYPOINT_NONE, and YAW.

Referenced by ImperialProbe_Hunt(), Interrogator_Hunt(), NPC_MoveToGoal(), Remote_Hunt(), Seeker_Hunt(), and Sentry_Hunt().

00161 {
00162         vec3_t          angles;
00163 
00164         //Clear the struct
00165         memset( &frameNavInfo, 0, sizeof( frameNavInfo ) );
00166 
00167         //Get our movement, if any
00168         if ( NPC_GetMoveInformation( frameNavInfo.direction, &frameNavInfo.distance ) == qfalse )
00169                 return qfalse;
00170 
00171         //Setup the return value
00172         *distance = frameNavInfo.distance;
00173 
00174         //For starters
00175         VectorCopy( frameNavInfo.direction, frameNavInfo.pathDirection );
00176 
00177         //If on a ladder, move appropriately
00178         if ( NPC->watertype & CONTENTS_LADDER )
00179         {
00180                 NPC_LadderMove( frameNavInfo.direction );
00181                 return qtrue;
00182         }
00183 
00184         //Attempt a straight move to goal
00185         if ( NPC_ClearPathToGoal( frameNavInfo.direction, NPCInfo->goalEntity ) == qfalse )
00186         {
00187                 //See if we're just stuck
00188                 if ( NAV_MoveToGoal( NPC, &frameNavInfo ) == WAYPOINT_NONE )
00189                 {
00190                         //Can't reach goal, just face
00191                         vectoangles( frameNavInfo.direction, angles );
00192                         NPCInfo->desiredYaw     = AngleNormalize360( angles[YAW] );             
00193                         VectorCopy( frameNavInfo.direction, out );
00194                         *distance = frameNavInfo.distance;
00195                         return qfalse;
00196                 }
00197 
00198                 frameNavInfo.flags |= NIF_MACRO_NAV;
00199         }
00200 
00201         //Avoid any collisions on the way
00202         if ( NAV_AvoidCollision( NPC, NPCInfo->goalEntity, &frameNavInfo ) == qfalse )
00203         {
00204                 //FIXME: Emit a warning, this is a worst case scenario
00205                 //FIXME: if we have a clear path to our goal (exluding bodies), but then this
00206                 //                      check (against bodies only) fails, shouldn't we fall back 
00207                 //                      to macro navigation?  Like so:
00208                 if ( !(frameNavInfo.flags&NIF_MACRO_NAV) )
00209                 {//we had a clear path to goal and didn't try macro nav, but can't avoid collision so try macro nav here
00210                         //See if we're just stuck
00211                         if ( NAV_MoveToGoal( NPC, &frameNavInfo ) == WAYPOINT_NONE )
00212                         {
00213                                 //Can't reach goal, just face
00214                                 vectoangles( frameNavInfo.direction, angles );
00215                                 NPCInfo->desiredYaw     = AngleNormalize360( angles[YAW] );             
00216                                 VectorCopy( frameNavInfo.direction, out );
00217                                 *distance = frameNavInfo.distance;
00218                                 return qfalse;
00219                         }
00220 
00221                         frameNavInfo.flags |= NIF_MACRO_NAV;
00222                 }
00223         }
00224 
00225         //Setup the return values
00226         VectorCopy( frameNavInfo.direction, out );
00227         *distance = frameNavInfo.distance;
00228 
00229         return qtrue;
00230 }

qboolean NPC_GetMoveDirectionAltRoute vec3_t  out,
float *  distance,
qboolean  tryStraight
 

Definition at line 239 of file NPC_move.c.

References gNPC_t::aiFlags, AngleNormalize360(), CONTENTS_LADDER, d_altRoutes, gNPC_t::desiredYaw, navInfo_s::direction, navInfo_s::distance, navInfo_s::flags, frameNavInfo, gNPC_t::goalEntity, vmCvar_t::integer, memcpy(), memset(), navInfo_t, NAVNEW_AvoidCollision(), NAVNEW_MoveToGoal(), NIF_MACRO_NAV, NPC, NPC_ClearPathToGoal(), NPC_GetMoveInformation(), NPCAI_BLOCKED, NPCInfo, navInfo_s::pathDirection, qboolean, qfalse, qtrue, vec3_t, vectoangles(), VectorCopy, gentity_s::watertype, WAYPOINT_NONE, and YAW.

Referenced by NPC_MoveToGoal().

00240 {
00241         vec3_t          angles;
00242 
00243         NPCInfo->aiFlags &= ~NPCAI_BLOCKED;
00244 
00245         //Clear the struct
00246         memset( &frameNavInfo, 0, sizeof( frameNavInfo ) );
00247 
00248         //Get our movement, if any
00249         if ( NPC_GetMoveInformation( frameNavInfo.direction, &frameNavInfo.distance ) == qfalse )
00250                 return qfalse;
00251 
00252         //Setup the return value
00253         *distance = frameNavInfo.distance;
00254 
00255         //For starters
00256         VectorCopy( frameNavInfo.direction, frameNavInfo.pathDirection );
00257 
00258         //If on a ladder, move appropriately
00259         if ( NPC->watertype & CONTENTS_LADDER )
00260         {
00261                 NPC_LadderMove( frameNavInfo.direction );
00262                 return qtrue;
00263         }
00264 
00265         //Attempt a straight move to goal
00266         if ( !tryStraight || NPC_ClearPathToGoal( frameNavInfo.direction, NPCInfo->goalEntity ) == qfalse )
00267         {//blocked
00268                 //Can't get straight to goal, use macro nav
00269                 if ( NAVNEW_MoveToGoal( NPC, &frameNavInfo ) == WAYPOINT_NONE )
00270                 {
00271                         //Can't reach goal, just face
00272                         vectoangles( frameNavInfo.direction, angles );
00273                         NPCInfo->desiredYaw     = AngleNormalize360( angles[YAW] );             
00274                         VectorCopy( frameNavInfo.direction, out );
00275                         *distance = frameNavInfo.distance;
00276                         return qfalse;
00277                 }
00278                 //else we are on our way
00279                 frameNavInfo.flags |= NIF_MACRO_NAV;
00280         }
00281         else
00282         {//we have no architectural problems, see if there are ents inthe way and try to go around them
00283                 //not blocked
00284                 if ( d_altRoutes.integer )
00285                 {//try macro nav
00286                         navInfo_t       tempInfo;
00287                         memcpy( &tempInfo, &frameNavInfo, sizeof( tempInfo ) );
00288                         if ( NAVNEW_AvoidCollision( NPC, NPCInfo->goalEntity, &tempInfo, qtrue, 5 ) == qfalse )
00289                         {//revert to macro nav
00290                                 //Can't get straight to goal, dump tempInfo and use macro nav
00291                                 if ( NAVNEW_MoveToGoal( NPC, &frameNavInfo ) == WAYPOINT_NONE )
00292                                 {
00293                                         //Can't reach goal, just face
00294                                         vectoangles( frameNavInfo.direction, angles );
00295                                         NPCInfo->desiredYaw     = AngleNormalize360( angles[YAW] );             
00296                                         VectorCopy( frameNavInfo.direction, out );
00297                                         *distance = frameNavInfo.distance;
00298                                         return qfalse;
00299                                 }
00300                                 //else we are on our way
00301                                 frameNavInfo.flags |= NIF_MACRO_NAV;
00302                         }
00303                         else
00304                         {//otherwise, either clear or can avoid
00305                                 memcpy( &frameNavInfo, &tempInfo, sizeof( frameNavInfo ) );
00306                         }
00307                 }
00308                 else
00309                 {//OR: just give up
00310                         if ( NAVNEW_AvoidCollision( NPC, NPCInfo->goalEntity, &frameNavInfo, qtrue, 30 ) == qfalse )
00311                         {//give up
00312                                 return qfalse;
00313                         }
00314                 }
00315         }
00316 
00317         //Setup the return values
00318         VectorCopy( frameNavInfo.direction, out );
00319         *distance = frameNavInfo.distance;
00320 
00321         return qtrue;
00322 }

ID_INLINE qboolean NPC_GetMoveInformation vec3_t  dir,
float *  distance
 

Definition at line 126 of file NPC_move.c.

References gNPC_t::blockedDest, entityShared_t::currentOrigin, gNPC_t::goalEntity, NPC, NPCInfo, NULL, qboolean, qfalse, qtrue, gentity_s::r, vec3_t, VectorCopy, VectorNormalize(), and VectorSubtract.

Referenced by NPC_GetMoveDirection(), and NPC_GetMoveDirectionAltRoute().

00127 {
00128         //NOTENOTE: Use path stacks!
00129 
00130         //Make sure we have somewhere to go
00131         if ( NPCInfo->goalEntity == NULL )
00132                 return qfalse;
00133 
00134         //Get our move info
00135         VectorSubtract( NPCInfo->goalEntity->r.currentOrigin, NPC->r.currentOrigin, dir );
00136         *distance = VectorNormalize( dir );
00137         
00138         VectorCopy( NPCInfo->goalEntity->r.currentOrigin, NPCInfo->blockedDest );
00139 
00140         return qtrue;
00141 }

qboolean NPC_MoveToGoal qboolean  tryStraight  ) 
 

Definition at line 382 of file NPC_move.c.

References AngleNormalize360(), BOTH_PAIN1, BOTH_PAIN18, BUTTON_WALKING, usercmd_s::buttons, gentity_s::client, gNPC_t::desiredPitch, gNPC_t::desiredYaw, gNPC_t::distToGoal, EF2_FLYING, playerState_s::eFlags2, usercmd_s::forwardmove, G_UcmdMoveForDir(), GetTime(), gNPC_t::lastPathAngles, entityState_s::legsAnim, NPC, NPC_CheckCombatMove(), NPC_GetMoveDirection(), NPC_GetMoveDirectionAltRoute(), NPCInfo, PITCH, PM_InKnockDown(), gclient_s::ps, qboolean, qfalse, qtrue, gNPCstats_e::runSpeed, gentity_s::s, playerState_s::speed, startTime, gNPC_t::stats, ucmd, vec3_t, vectoangles(), playerState_s::velocity, gNPCstats_e::walkSpeed, and YAW.

Referenced by ATST_Hunt(), ATST_Patrol(), Droid_Patrol(), Howler_Combat(), Howler_Move(), Howler_Patrol(), ImperialProbe_Patrol(), Mark1_Hunt(), Mark1_Patrol(), Mark2_Hunt(), Mark2_Patrol(), MineMonster_Combat(), MineMonster_Idle(), MineMonster_Move(), MineMonster_Patrol(), NPC_BSCinematic(), NPC_BSDefault(), NPC_BSFlee(), NPC_BSGM_Patrol(), NPC_BSGrenadier_Patrol(), NPC_BSHuntAndKill(), NPC_BSIdle(), NPC_BSJedi_FollowLeader(), NPC_BSPatrol(), NPC_BSRun(), NPC_BSRunAndShoot(), NPC_BSSearch(), NPC_BSSniper_Patrol(), NPC_BSST_Investigate(), NPC_BSST_Patrol(), NPC_BSWander(), NPC_Sentry_Patrol(), NPC_SlideMoveToGoal(), Rancor_Combat(), Rancor_Idle(), Rancor_Move(), Rancor_Patrol(), Remote_Patrol(), Seeker_FollowOwner(), Wampa_Idle(), Wampa_Move(), and Wampa_Patrol().

00383 {
00384         float   distance;
00385         vec3_t  dir;
00386 
00387 #if     AI_TIMERS
00388         int     startTime = GetTime(0);
00389 #endif//        AI_TIMERS
00390         //If taking full body pain, don't move
00391         if ( PM_InKnockDown( &NPC->client->ps ) || ( ( NPC->s.legsAnim >= BOTH_PAIN1 ) && ( NPC->s.legsAnim <= BOTH_PAIN18 ) ) )
00392         {
00393                 return qtrue;
00394         }
00395 
00396         /*
00397         if( NPC->s.eFlags & EF_LOCKED_TO_WEAPON )
00398         {//If in an emplaced gun, never try to navigate!
00399                 return qtrue;
00400         }
00401         */
00402         //rwwFIXMEFIXME: emplaced support
00403 
00404         //FIXME: if can't get to goal & goal is a target (enemy), try to find a waypoint that has line of sight to target, at least?
00405         //Get our movement direction
00406 #if 1
00407         if ( NPC_GetMoveDirectionAltRoute( dir, &distance, tryStraight ) == qfalse )
00408 #else
00409         if ( NPC_GetMoveDirection( dir, &distance ) == qfalse )
00410 #endif
00411                 return qfalse;
00412 
00413         NPCInfo->distToGoal             = distance;
00414 
00415         //Convert the move to angles
00416         vectoangles( dir, NPCInfo->lastPathAngles );
00417         if ( (ucmd.buttons&BUTTON_WALKING) )
00418         {
00419                 NPC->client->ps.speed = NPCInfo->stats.walkSpeed;
00420         }
00421         else
00422         {
00423                 NPC->client->ps.speed = NPCInfo->stats.runSpeed;
00424         }
00425 
00426         //FIXME: still getting ping-ponging in certain cases... !!!  Nav/avoidance error?  WTF???!!!
00427         //If in combat move, then move directly towards our goal
00428         if ( NPC_CheckCombatMove() )
00429         {//keep current facing
00430                 G_UcmdMoveForDir( NPC, &ucmd, dir );
00431         }
00432         else
00433         {//face our goal
00434                 //FIXME: strafe instead of turn if change in dir is small and temporary
00435                 NPCInfo->desiredPitch   = 0.0f;
00436                 NPCInfo->desiredYaw             = AngleNormalize360( NPCInfo->lastPathAngles[YAW] );
00437                 
00438                 //Pitch towards the goal and also update if flying or swimming
00439                 if ( (NPC->client->ps.eFlags2&EF2_FLYING) )//moveType == MT_FLYSWIM )
00440                 {
00441                         NPCInfo->desiredPitch = AngleNormalize360( NPCInfo->lastPathAngles[PITCH] );
00442                         
00443                         if ( dir[2] )
00444                         {
00445                                 float scale = (dir[2] * distance);
00446                                 if ( scale > 64 )
00447                                 {
00448                                         scale = 64;
00449                                 }
00450                                 else if ( scale < -64 )
00451                                 {
00452                                         scale = -64;
00453                                 }
00454                                 NPC->client->ps.velocity[2] = scale;
00455                                 //NPC->client->ps.velocity[2] = (dir[2] > 0) ? 64 : -64;
00456                         }
00457                 }
00458 
00459                 //Set any final info
00460                 ucmd.forwardmove = 127;
00461         }
00462 
00463 #if     AI_TIMERS
00464         navTime += GetTime( startTime );
00465 #endif//        AI_TIMERS
00466         return qtrue;
00467 }

qboolean NPC_SlideMoveToGoal void   ) 
 

Definition at line 476 of file NPC_move.c.

References gentity_s::client, gNPC_t::combatMove, gNPC_t::desiredYaw, NPC, NPC_MoveToGoal(), NPCInfo, gclient_s::ps, qboolean, qtrue, playerState_s::viewangles, and YAW.

Referenced by NPC_BSFollowLeader(), and NPC_BSMove().

00477 {
00478         float   saveYaw = NPC->client->ps.viewangles[YAW];
00479         qboolean ret;
00480 
00481         NPCInfo->combatMove = qtrue;
00482         
00483         ret = NPC_MoveToGoal( qtrue );
00484 
00485         NPCInfo->desiredYaw     = saveYaw;
00486 
00487         return ret;
00488 }

qboolean PM_InKnockDown playerState_t ps  ) 
 

Definition at line 1216 of file bg_panimate.c.

01217 {
01218         switch ( (ps->legsAnim) )
01219         {
01220         case BOTH_KNOCKDOWN1:
01221         case BOTH_KNOCKDOWN2:
01222         case BOTH_KNOCKDOWN3:
01223         case BOTH_KNOCKDOWN4:
01224         case BOTH_KNOCKDOWN5:
01225                 return qtrue;
01226                 break;
01227         case BOTH_GETUP1:
01228         case BOTH_GETUP2:
01229         case BOTH_GETUP3:
01230         case BOTH_GETUP4:
01231         case BOTH_GETUP5:
01232         case BOTH_FORCE_GETUP_F1:
01233         case BOTH_FORCE_GETUP_F2:
01234         case BOTH_FORCE_GETUP_B1:
01235         case BOTH_FORCE_GETUP_B2:
01236         case BOTH_FORCE_GETUP_B3:
01237         case BOTH_FORCE_GETUP_B4:
01238         case BOTH_FORCE_GETUP_B5:
01239         case BOTH_GETUP_BROLL_B:
01240         case BOTH_GETUP_BROLL_F:
01241         case BOTH_GETUP_BROLL_L:
01242         case BOTH_GETUP_BROLL_R:
01243         case BOTH_GETUP_FROLL_B:
01244         case BOTH_GETUP_FROLL_F:
01245         case BOTH_GETUP_FROLL_L:
01246         case BOTH_GETUP_FROLL_R:
01247                 if ( ps->legsTimer )
01248                 {
01249                         return qtrue;
01250                 }
01251                 break;
01252         }
01253         return qfalse;
01254 }


Variable Documentation

navInfo_t frameNavInfo
 

Definition at line 14 of file NPC_move.c.

Referenced by NAV_GetLastMove(), NPC_GetMoveDirection(), and NPC_GetMoveDirectionAltRoute().