예제 #1
0
/*
-------------------------
NAVNEW_Bypass
-------------------------
*/
qboolean NAVNEW_Bypass( gentity_t *self, gentity_t *blocker, vec3_t blocked_dir, float blocked_dist, vec3_t movedir, qboolean setBlockedInfo ) 
{
	vec3_t	moveangles, right;

	//Draw debug info if requested
	if ( NAVDEBUG_showCollision )
	{
		G_DrawEdge( self->r.currentOrigin, blocker->r.currentOrigin, EDGE_NORMAL );
	}

	vectoangles( movedir, moveangles );
	moveangles[2] = 0;
	AngleVectors( moveangles, NULL, right, NULL );

	//Check to see what dir the other guy is moving in (if any) and pick the opposite dir
	if ( NAVNEW_DanceWithBlocker( self, blocker, movedir, right ) )
	{
		return qtrue;
	}

	//Okay, so he's not moving to my side, see which side of him is most clear
	if ( NAVNEW_SidestepBlocker( self, blocker, blocked_dir, blocked_dist, movedir, right ) )
	{
		return qtrue;
	}

	//Neither side is clear, tell him to step aside
	NAVNEW_PushBlocker( self, blocker, right, setBlockedInfo );

	return qfalse;
}
예제 #2
0
파일: NPC_move.c 프로젝트: jwginge/ojpa
qboolean NPC_TryJump_Final()
{
	vec3_t	targetDirection;
	float	targetDistanceXY;
	float	targetDistanceZ;
	int		sideTryCount;

	qboolean	WithinForceJumpRange;

	// Get The Direction And Distances To The Target
	//-----------------------------------------------
	VectorSubtract(NPCInfo->jumpDest, NPC->r.currentOrigin, targetDirection);
	targetDirection[2]	= 0.0f;
	targetDistanceXY	= VectorNormalize(targetDirection);
	targetDistanceZ		= NPCInfo->jumpDest[2] - NPC->r.currentOrigin[2];

	if ((targetDistanceXY>NPCInfo->jumpMaxXYDist) ||
		(targetDistanceZ<NPCInfo->jumpMazZDist))
	{
		return qfalse;
	}


	// Test To See If There Is A Wall Directly In Front Of Actor, If So, Backup Some
	//-------------------------------------------------------------------------------
	if (TIMER_Done(NPC, "jumpBackupDebounce"))
	{
		vec3_t	actorProjectedTowardTarget;
		VectorMA(NPC->r.currentOrigin, NPC_JUMP_PREP_BACKUP_DIST, targetDirection, actorProjectedTowardTarget);
		trap_Trace(&mJumpTrace, NPC->r.currentOrigin, vec3_origin, vec3_origin, actorProjectedTowardTarget, NPC->s.number, NPC->clipmask);
		if ((mJumpTrace.fraction < 1.0f) ||
			(mJumpTrace.allsolid) ||
			(mJumpTrace.startsolid))
		{
			if (NAVDEBUG_showCollision)
			{
				G_DrawEdge(NPC->r.currentOrigin, actorProjectedTowardTarget, EDGE_RED_TWOSECOND);	// TryJump
			}

			// TODO: We may want to test to see if it is safe to back up here?
			NPCInfo->jumpBackupTime = level.time + 1000;
			TIMER_Set(NPC, "jumpBackupDebounce", 5000);
			return qtrue;
		}
	}


//	bool	Wounded					= (NPC->health < 150);
//	bool	OnLowerLedge			= ((targetDistanceZ<-80.0f) && (targetDistanceZ>-200.0f));
//	bool	WithinNormalJumpRange	= ((targetDistanceZ<32.0f)  && (targetDistanceXY<200.0f));
	WithinForceJumpRange = (qboolean)(((float)fabs(targetDistanceZ)>0) || (targetDistanceXY>128));

/*	if (Wounded && OnLowerLedge)
	{
		ucmd.forwardmove	= 127;
		VectorClear(NPC->client->ps.moveDir);
		TIMER_Set(NPC, "duck", -level.time);
		return qtrue;
	}
	
	if (WithinNormalJumpRange)
	{
		ucmd.upmove			= 127;
		ucmd.forwardmove	= 127;
		VectorClear(NPC->client->ps.moveDir);
		TIMER_Set(NPC, "duck", -level.time);
		return qtrue;
	}
*/

	if (!WithinForceJumpRange)
	{
		return qfalse;
	}



	// If There Is Any Chance That This Jump Will Land On An Enemy, Try 8 Different Traces Around The Target
	//-------------------------------------------------------------------------------------------------------
	if (NPCInfo->jumpTarget)
	{
		float	minSafeRadius	= (NPC->r.maxs[0]*1.5f) + (NPCInfo->jumpTarget->r.maxs[0]*1.5f);
		float	minSafeRadiusSq	= (minSafeRadius * minSafeRadius);

		if (DistanceSquared(NPCInfo->jumpDest, NPCInfo->jumpTarget->r.currentOrigin)<minSafeRadiusSq)
		{
			vec3_t	startPos;
			vec3_t	floorPos;
			VectorCopy(NPCInfo->jumpDest, startPos);

			floorPos[2] = NPCInfo->jumpDest[2] + (NPC->r.mins[2]-32);

			for (sideTryCount=0; sideTryCount<8; sideTryCount++)
			{
				NPCInfo->jumpSide++;
				if ( NPCInfo->jumpSide > 7 )
				{
					NPCInfo->jumpSide = 0;
				}

				switch ( NPCInfo->jumpSide )
				{
				case 0:
					NPCInfo->jumpDest[0] = startPos[0] + minSafeRadius;
					NPCInfo->jumpDest[1] = startPos[1];
					break;
				case 1:
					NPCInfo->jumpDest[0] = startPos[0] + minSafeRadius;
					NPCInfo->jumpDest[1] = startPos[1] + minSafeRadius;
					break;
				case 2:
					NPCInfo->jumpDest[0] = startPos[0];
					NPCInfo->jumpDest[1] = startPos[1] + minSafeRadius;
					break;
				case 3:
					NPCInfo->jumpDest[0] = startPos[0] - minSafeRadius;
					NPCInfo->jumpDest[1] = startPos[1] + minSafeRadius;
					break;
				case 4:
					NPCInfo->jumpDest[0] = startPos[0] - minSafeRadius;
					NPCInfo->jumpDest[1] = startPos[1];
					break;
				case 5:
					NPCInfo->jumpDest[0] = startPos[0] - minSafeRadius;
					NPCInfo->jumpDest[1] = startPos[1] - minSafeRadius;
					break;
				case 6:
					NPCInfo->jumpDest[0] = startPos[0];
					NPCInfo->jumpDest[1] = startPos[1] - minSafeRadius;
					break;
				case 7:
					NPCInfo->jumpDest[0] = startPos[0] + minSafeRadius;
					NPCInfo->jumpDest[1] = startPos[1] -=minSafeRadius;
					break;
				}

				floorPos[0] = NPCInfo->jumpDest[0];
				floorPos[1] = NPCInfo->jumpDest[1];

				trap_Trace(&mJumpTrace, NPCInfo->jumpDest, NPC->r.mins, NPC->r.maxs, floorPos, (NPCInfo->jumpTarget)?(NPCInfo->jumpTarget->s.number):(NPC->s.number), (NPC->clipmask|CONTENTS_BOTCLIP));
				if ((mJumpTrace.fraction<1.0f) && 
					(!mJumpTrace.allsolid) && 
					(!mJumpTrace.startsolid))
				{
					break;
				}

				if ( NAVDEBUG_showCollision )
				{
					G_DrawEdge( NPCInfo->jumpDest, floorPos, EDGE_RED_TWOSECOND );
				}
			}

			// If All Traces Failed, Just Try Going Right Back At The Target Location
			//------------------------------------------------------------------------
			if ((mJumpTrace.fraction>=1.0f) || 
				(mJumpTrace.allsolid) || 
				(mJumpTrace.startsolid))
			{
				VectorCopy(startPos, NPCInfo->jumpDest);
			}
		}
	}
	
	// Now, Actually Try The Jump To The Dest Target
	//-----------------------------------------------
	if (NPC_Jump(NPCInfo->jumpDest, (NPCInfo->jumpTarget)?(NPCInfo->jumpTarget->s.number):(NPC->s.number)))
	{
		// We Made IT!
		//-------------
		NPC_JumpAnimation();
		NPC_JumpSound();

		NPC->client->ps.fd.forceJumpZStart	 = NPC->r.currentOrigin[2];
		//NPC->client->ps.pm_flags			|= PMF_JUMPING;
		NPC->client->ps.weaponTime			 = NPC->client->ps.torsoTimer;
		NPC->client->ps.fd.forcePowersActive	|= ( 1 << FP_LEVITATION );
		ucmd.forwardmove					 = 0;
		NPCInfo->jumpTime					 = 1;

		VectorClear(NPC->client->ps.moveDir);
		TIMER_Set(NPC, "duck", -level.time);

		return qtrue;
	}
	return qfalse;
}
예제 #3
0
파일: NPC_move.c 프로젝트: jwginge/ojpa
static qboolean NPC_Jump( vec3_t dest, int goalEntNum )
{//FIXME: if land on enemy, knock him down & jump off again
	float	targetDist, travelTime, impactDist, bestImpactDist = Q3_INFINITE;//fireSpeed, 
	float originalShotSpeed, shotSpeed, speedStep = 50.0f, minShotSpeed = 30.0f, maxShotSpeed = 500.0f;
	qboolean belowBlocked = qfalse, aboveBlocked = qfalse;
	vec3_t	targetDir, shotVel, failCase; 
	trace_t	trace;
	trajectory_t	tr;
	qboolean	blocked;
	int		elapsedTime, timeStep = 250, hitCount = 0, aboveTries = 0, belowTries = 0, maxHits = 10;
	vec3_t	lastPos, testPos, bottom;

	VectorSubtract( dest, NPC->r.currentOrigin, targetDir );
	targetDist = VectorNormalize( targetDir );
	//make our shotSpeed reliant on the distance
	originalShotSpeed = targetDist;//DistanceHorizontal( dest, NPC->currentOrigin )/2.0f;
	if ( originalShotSpeed > maxShotSpeed )
	{
		originalShotSpeed = maxShotSpeed;
	}
	else if ( originalShotSpeed < minShotSpeed )
	{
		originalShotSpeed = minShotSpeed;
	}
	shotSpeed = originalShotSpeed;

	while ( hitCount < maxHits )
	{
		VectorScale( targetDir, shotSpeed, shotVel );
		travelTime = targetDist/shotSpeed;
		shotVel[2] += travelTime * 0.5 * NPC->client->ps.gravity;

		if ( !hitCount )		
		{//save the first one as the worst case scenario
			VectorCopy( shotVel, failCase );
		}

		if ( 1 )//tracePath )
		{//do a rough trace of the path
			blocked = qfalse;

			VectorCopy( NPC->r.currentOrigin, tr.trBase );
			VectorCopy( shotVel, tr.trDelta );
			tr.trType = TR_GRAVITY;
			tr.trTime = level.time;
			travelTime *= 1000.0f;
			VectorCopy( NPC->r.currentOrigin, lastPos );
			
			//This may be kind of wasteful, especially on long throws... use larger steps?  Divide the travelTime into a certain hard number of slices?  Trace just to apex and down?
			for ( elapsedTime = timeStep; elapsedTime < floor(travelTime)+timeStep; elapsedTime += timeStep )
			{
				if ( (float)elapsedTime > travelTime )
				{//cap it
					elapsedTime = floor( travelTime );
				}
				BG_EvaluateTrajectory( &tr, level.time + elapsedTime, testPos );
				//F**K IT, always check for do not enter...
				trap_Trace( &trace, lastPos, NPC->r.mins, NPC->r.maxs, testPos, NPC->s.number, NPC->clipmask|CONTENTS_BOTCLIP );
				/*
				if ( testPos[2] < lastPos[2] 
					&& elapsedTime < floor( travelTime ) )
				{//going down, haven't reached end, ignore botclip
					gi.trace( &trace, lastPos, NPC->mins, NPC->maxs, testPos, NPC->s.number, NPC->clipmask );
				}
				else
				{//going up, check for botclip
					gi.trace( &trace, lastPos, NPC->mins, NPC->maxs, testPos, NPC->s.number, NPC->clipmask|CONTENTS_BOTCLIP );
				}
				*/

				if ( trace.allsolid || trace.startsolid )
				{//started in solid
					if ( NAVDEBUG_showCollision )
					{
						G_DrawEdge( lastPos, trace.endpos, EDGE_RED_TWOSECOND );
					}
					return qfalse;//you're hosed, dude
				}
				if ( trace.fraction < 1.0f )
				{//hit something
					if ( NAVDEBUG_showCollision )
					{
						G_DrawEdge( lastPos, trace.endpos, EDGE_RED_TWOSECOND );	// TryJump
					}
					if ( trace.entityNum == goalEntNum )
					{//hit the enemy, that's bad!
						blocked = qtrue;
						/*
						if ( g_entities[goalEntNum].client && g_entities[goalEntNum].client->ps.groundEntityNum == ENTITYNUM_NONE )
						{//bah, would collide in mid-air, no good
							blocked = qtrue;
						}
						else
						{//he's on the ground, good enough, I guess
							//Hmm, don't want to land on him, though...?
						}
						*/
						break;
					}
					else 
					{
						if ( trace.contents & CONTENTS_BOTCLIP )
						{//hit a do-not-enter brush
							blocked = qtrue;
							break;
						}
						if ( trace.plane.normal[2] > 0.7 && DistanceSquared( trace.endpos, dest ) < 4096 )//hit within 64 of desired location, should be okay
						{//close enough!
							break;
						}
						else
						{//FIXME: maybe find the extents of this brush and go above or below it on next try somehow?
							impactDist = DistanceSquared( trace.endpos, dest );
							if ( impactDist < bestImpactDist )
							{
								bestImpactDist = impactDist;
								VectorCopy( shotVel, failCase );
							}
							blocked = qtrue;
							break;
						}
					}
				}
				else
				{
					if ( NAVDEBUG_showCollision )
					{
						G_DrawEdge( lastPos, testPos, EDGE_WHITE_TWOSECOND );	// TryJump
					}
				}
				if ( elapsedTime == floor( travelTime ) )
				{//reached end, all clear
					if ( trace.fraction >= 1.0f )
					{//hmm, make sure we'll land on the ground...
						//FIXME: do we care how far below ourselves or our dest we'll land?
						VectorCopy( trace.endpos, bottom );
						bottom[2] -= 128;
						trap_Trace( &trace, trace.endpos, NPC->r.mins, NPC->r.maxs, bottom, NPC->s.number, NPC->clipmask );
						if ( trace.fraction >= 1.0f )
						{//would fall too far
							blocked = qtrue;
						}
					}
					break;
				}
				else
				{
					//all clear, try next slice
					VectorCopy( testPos, lastPos );
				}
			}
			if ( blocked )
			{//hit something, adjust speed (which will change arc)
				hitCount++;
				//alternate back and forth between trying an arc slightly above or below the ideal
				if ( (hitCount%2) && !belowBlocked )
				{//odd
					belowTries++;
					shotSpeed = originalShotSpeed - (belowTries*speedStep);
				}
				else if ( !aboveBlocked )
				{//even
					aboveTries++;
					shotSpeed = originalShotSpeed + (aboveTries*speedStep);
				}
				else
				{//can't go any higher or lower
					hitCount = maxHits;
					break;
				}
				if ( shotSpeed > maxShotSpeed )
				{
					shotSpeed = maxShotSpeed;
					aboveBlocked = qtrue;
				}
				else if ( shotSpeed < minShotSpeed )
				{
					shotSpeed = minShotSpeed;
					belowBlocked = qtrue;
				}
			}
			else
			{//made it!
				break;
			}
		}
		else
		{//no need to check the path, go with first calc
			break;
		}
	}

	if ( hitCount >= maxHits )
	{//NOTE: worst case scenario, use the one that impacted closest to the target (or just use the first try...?)
		return qfalse;
		//NOTE: or try failcase?
		//VectorCopy( failCase, NPC->client->ps.velocity );
		//return qtrue;
	}
	VectorCopy( shotVel, NPC->client->ps.velocity );
	return qtrue;
}
예제 #4
0
/*
-------------------------
NAVNEW_MoveToGoal
-------------------------
*/
int	NAVNEW_MoveToGoal( gentity_t *self, navInfo_t *info )
{
	int			bestNode = WAYPOINT_NONE;
	qboolean	foundClearPath = qfalse;
	vec3_t		origin;
	navInfo_t	tempInfo;
	qboolean	setBlockedInfo = qtrue;
	qboolean	/*inBestWP, */inGoalWP/*, goalWPFailed = qfalse*/;
	int			numTries = 0;

	memcpy( &tempInfo, info, sizeof( tempInfo ) );

	//Must have a goal entity to move there
	if( self->NPC->goalEntity == NULL )
		return WAYPOINT_NONE;

	if ( self->waypoint == WAYPOINT_NONE && self->noWaypointTime > level.time )
	{//didn't have a valid one in about the past second, don't look again just yet
		return WAYPOINT_NONE;
	}
	if ( self->NPC->goalEntity->waypoint == WAYPOINT_NONE && self->NPC->goalEntity->noWaypointTime > level.time )
	{//didn't have a valid one in about the past second, don't look again just yet
		return WAYPOINT_NONE;
	}
	if ( self->noWaypointTime > level.time &&
		self->NPC->goalEntity->noWaypointTime > level.time )
	{//just use current waypoints
		bestNode = trap->Nav_GetBestNodeAltRoute2( self->waypoint, self->NPC->goalEntity->waypoint, bestNode );
	}
	//FIXME!!!!: this is making them wiggle back and forth between waypoints
	else if ( (bestNode = trap->Nav_GetBestPathBetweenEnts( (sharedEntity_t *)self, (sharedEntity_t *)self->NPC->goalEntity, NF_CLEAR_PATH )) == NODE_NONE )//!NAVNEW_GetWaypoints( self, qtrue ) )
	{//one of us didn't have a valid waypoint!
		if ( self->waypoint == NODE_NONE )
		{//don't even try to find one again for a bit
			self->noWaypointTime = level.time + Q_irand( 500, 1500 );
		}
		if ( self->NPC->goalEntity->waypoint == NODE_NONE )
		{//don't even try to find one again for a bit
			self->NPC->goalEntity->noWaypointTime = level.time + Q_irand( 500, 1500 );
		}
		return WAYPOINT_NONE;
	}
	else
	{
		if ( self->NPC->goalEntity->noWaypointTime < level.time )
		{
			self->NPC->goalEntity->noWaypointTime = level.time + Q_irand( 500, 1500 );
		}
	}

	while( !foundClearPath )
	{
		/*inBestWP = */inGoalWP = qfalse;
		/*
		bestNode = trap->Nav_GetBestNodeAltRoute( self->waypoint, self->NPC->goalEntity->waypoint, bestNode );
		*/

		if ( bestNode == WAYPOINT_NONE )
		{
			goto failed;
		}

		//see if we can get directly to the next node off bestNode en route to goal's node...
		//NOTE: shouldn't be necc. now
		/*
		int oldBestNode = bestNode;
		bestNode = NAV_TestBestNode( self, self->waypoint, bestNode, qtrue );//, self->NPC->goalEntity->waypoint );// 
		//NOTE: Guaranteed to return something
		if ( bestNode != oldBestNode )
		{//we were blocked somehow
			if ( setBlockedInfo )
			{
				self->NPC->aiFlags |= NPCAI_BLOCKED;
				trap->Nav_GetNodePosition( oldBestNode, NPCInfo->blockedDest );
			}
		}
		*/
		trap->Nav_GetNodePosition( bestNode, origin );
		/*
		if ( !goalWPFailed )
		{//we haven't already tried to go straight to goal or goal's wp
			if ( bestNode == self->NPC->goalEntity->waypoint )
			{//our bestNode is the goal's wp
				if ( NAV_HitNavGoal( self->r.currentOrigin, self->r.mins, self->r.maxs, origin, trap->Nav_GetNodeRadius( bestNode ), FlyingCreature( self ) ) )
				{//we're in the goal's wp
					inGoalWP = qtrue;
					//we're in the goalEntity's waypoint already
					//so head for the goalEntity since we know it's clear of architecture
					//FIXME: this is pretty stupid because the NPCs try to go straight
					//		towards their goal before then even try macro_nav...
					VectorCopy( self->NPC->goalEntity->r.currentOrigin, origin );
				}
			}
		}
		*/
		if ( !inGoalWP )
		{//not heading straight for goal
			if ( bestNode == self->waypoint )
			{//we know it's clear or architecture
				//trap->Nav_GetNodePosition( self->waypoint, origin );
				/*
				if ( NAV_HitNavGoal( self->r.currentOrigin, self->r.mins, self->r.maxs, origin, trap->Nav_GetNodeRadius( bestNode ), FlyingCreature( self ) ) )
				{//we're in the wp we're heading for already
					inBestWP = qtrue;
				}
				*/
			}
			else
			{//heading to an edge off our confirmed clear waypoint... make sure it's clear
				//it it's not, bestNode will fall back to our waypoint
				int oldBestNode = bestNode;
				bestNode = NAV_TestBestNode( self, self->waypoint, bestNode, qtrue );
				if ( bestNode == self->waypoint )
				{//we fell back to our waypoint, reset the origin
					self->NPC->aiFlags |= NPCAI_BLOCKED;
					trap->Nav_GetNodePosition( oldBestNode, NPCS.NPCInfo->blockedDest );
					trap->Nav_GetNodePosition( bestNode, origin );
				}
			}
		}
		//Com_Printf( "goalwp = %d, mywp = %d, node = %d, origin = %s\n", self->NPC->goalEntity->waypoint, self->waypoint, bestNode, vtos(origin) );

		memcpy( &tempInfo, info, sizeof( tempInfo ) );
		VectorSubtract( origin, self->r.currentOrigin, tempInfo.direction );
		VectorNormalize( tempInfo.direction );

		//NOTE: One very important thing NAVNEW_AvoidCollision does is
		//		it actually CHANGES the value of "direction" - it changes it to
		//		whatever dir you need to go in to avoid the obstacle...
		foundClearPath = NAVNEW_AvoidCollision( self, self->NPC->goalEntity, &tempInfo, setBlockedInfo, 5 );

		if ( !foundClearPath )
		{//blocked by an ent
			if ( inGoalWP )
			{//we were heading straight for the goal, head for the goal's wp instead
				trap->Nav_GetNodePosition( bestNode, origin );
				foundClearPath = NAVNEW_AvoidCollision( self, self->NPC->goalEntity, &tempInfo, setBlockedInfo, 5 );
			}
		}

		if ( foundClearPath )
		{//clear!
			//If we got set to blocked, clear it
			NPC_ClearBlocked( self );
			//Take the dir
			memcpy( info, &tempInfo, sizeof( *info ) );
			if ( self->s.weapon == WP_SABER )
			{//jedi
				if ( info->direction[2] * info->distance > 64 )
				{
					self->NPC->aiFlags |= NPCAI_BLOCKED;
					VectorCopy( origin, NPCS.NPCInfo->blockedDest );
					goto failed;
				}
			}
		}
		else
		{//blocked by ent!
			if ( setBlockedInfo )
			{
				self->NPC->aiFlags |= NPCAI_BLOCKED;
				trap->Nav_GetNodePosition( bestNode, NPCS.NPCInfo->blockedDest );
			}
			//Only set blocked info first time
			setBlockedInfo = qfalse;

			if ( inGoalWP )
			{//we headed for our goal and failed and our goal's WP and failed
				if ( self->waypoint == self->NPC->goalEntity->waypoint )
				{//our waypoint is our goal's waypoint, nothing we can do
					//remember that this node is blocked
					trap->Nav_AddFailedNode( (sharedEntity_t *)self, self->waypoint );
					goto failed;
				}
				else
				{//try going for our waypoint this time
					inGoalWP = qfalse;
				}
			}
			else if ( bestNode != self->waypoint )
			{//we headed toward our next waypoint (instead of our waypoint) and failed
				if ( d_altRoutes.integer )
				{//mark this edge failed and try our waypoint
					//NOTE: don't assume there is something blocking the direct path
					//			between my waypoint and the bestNode... I could be off
					//			that path because of collision avoidance...
					if ( d_patched.integer &&//use patch-style navigation
 						( !trap->Nav_NodesAreNeighbors( self->waypoint, bestNode )
						|| NAVNEW_TestNodeConnectionBlocked( self->waypoint, bestNode, self, self->NPC->goalEntity->s.number, qfalse, qtrue ) ) )
					{//the direct path between these 2 nodes is blocked by an ent
						trap->Nav_AddFailedEdge( self->s.number, self->waypoint, bestNode );
					}
					bestNode = self->waypoint;
				}
				else
				{
					//we should stop
					goto failed;
				}
			}
			else 
			{//we headed for *our* waypoint and couldn't get to it
				if ( d_altRoutes.integer )
				{
					//remember that this node is blocked
					trap->Nav_AddFailedNode( (sharedEntity_t *)self, self->waypoint );
					//Now we should get our waypoints again
					//FIXME: cache the trace-data for subsequent calls as only the route info would have changed
					//if ( (bestNode = trap->Nav_GetBestPathBetweenEnts( self, self->NPC->goalEntity, NF_CLEAR_PATH )) == NODE_NONE )//!NAVNEW_GetWaypoints( self, qfalse ) )
					{//one of our waypoints is WAYPOINT_NONE now
						goto failed;
					}
				}
				else
				{
					//we should stop
					goto failed;
				}
			}

			if ( ++numTries >= 10 )
			{
				goto failed;
			}
		}
	}

//finish:
	//Draw any debug info, if requested
	if ( NAVDEBUG_showEnemyPath )
	{
		vec3_t	dest, start;

		//Get the positions
		trap->Nav_GetNodePosition( self->NPC->goalEntity->waypoint, dest );
		trap->Nav_GetNodePosition( bestNode, start );

		//Draw the route
		G_DrawNode( start, NODE_START );
		if ( bestNode != self->waypoint )
		{
			vec3_t	wpPos;
			trap->Nav_GetNodePosition( self->waypoint, wpPos );
			G_DrawNode( wpPos, NODE_NAVGOAL );
		}
		G_DrawNode( dest, NODE_GOAL );
		G_DrawEdge( dest, self->NPC->goalEntity->r.currentOrigin, EDGE_PATH );
		G_DrawNode( self->NPC->goalEntity->r.currentOrigin, NODE_GOAL );
		trap->Nav_ShowPath( bestNode, self->NPC->goalEntity->waypoint );
	}

	self->NPC->shoveCount = 0;

	//let me keep this waypoint for a while
	if ( self->noWaypointTime < level.time )
	{
		self->noWaypointTime = level.time + Q_irand( 500, 1500 );
	}
	return bestNode;

failed:
	//FIXME: What we should really do here is have a list of the goal's and our
	//		closest clearpath waypoints, ranked.  If the first set fails, try the rest
	//		until there are no alternatives.

	trap->Nav_GetNodePosition( self->waypoint, origin );

	//do this to avoid ping-ponging?
	return WAYPOINT_NONE;
	/*
	//this was causing ping-ponging
	if ( DistanceSquared( origin, self->r.currentOrigin ) < 16 )//woo, magic number
	{//We're right up on our waypoint, so that won't help, return none
		//Or maybe find the nextbest here?
		return WAYPOINT_NONE;
	}
	else
	{//Try going to our waypoint
		bestNode = self->waypoint;

		VectorSubtract( origin, self->r.currentOrigin, info.direction );
		VectorNormalize( info.direction );
	}
	
	goto finish;
	*/
}
예제 #5
0
/*
-------------------------
NAVNEW_AvoidCollision
-------------------------
*/
qboolean NAVNEW_AvoidCollision( gentity_t *self, gentity_t *goal, navInfo_t *info, qboolean setBlockedInfo, int blockedMovesLimit )
{
	vec3_t	movedir;
	vec3_t	movepos;

	//Cap our distance
	if ( info->distance > MAX_COLL_AVOID_DIST )
	{
		info->distance = MAX_COLL_AVOID_DIST;
	}

	//Get an end position
	VectorMA( self->r.currentOrigin, info->distance, info->direction, movepos );
	VectorCopy( info->direction, movedir );

	//Now test against entities
	if ( NAV_CheckAhead( self, movepos, &info->trace, CONTENTS_BODY ) == qfalse )
	{
		//Get the blocker
		info->blocker = &g_entities[ info->trace.entityNum ];
		info->flags |= NIF_COLLISION;

		//Ok to hit our goal entity
		if ( goal == info->blocker )
			return qtrue;

		if ( setBlockedInfo )
		{
			if ( self->NPC->consecutiveBlockedMoves > blockedMovesLimit  )
			{
				if ( d_patched.integer )
				{//use patch-style navigation
					self->NPC->consecutiveBlockedMoves++;
				}
				NPC_SetBlocked( self, info->blocker );
				return qfalse;
			}
			self->NPC->consecutiveBlockedMoves++;
		}
		//See if we're moving along with them
		//if ( NAVNEW_TrueCollision( self, info->blocker, movedir, info->direction ) == qfalse )
		//	return qtrue;

		//Test for blocking by standing on goal
		if ( NAV_TestForBlocked( self, goal, info->blocker, info->distance, &info->flags ) == qtrue )
			return qfalse;

		//If the above function said we're blocked, don't do the extra checks
		/*
		if ( info->flags & NIF_BLOCKED )
			return qtrue;
		*/

		//See if we can get that entity to move out of our way
		if ( NAVNEW_ResolveEntityCollision( self, info->blocker, movedir, info->pathDirection, setBlockedInfo ) == qfalse )
			return qfalse;

		VectorCopy( movedir, info->direction );
		
		return qtrue;
	}
	else
	{
		if ( setBlockedInfo )
		{
			self->NPC->consecutiveBlockedMoves = 0;
		}
	}

	//Our path is clear, just move there
	if ( NAVDEBUG_showCollision )
	{
		G_DrawEdge( self->r.currentOrigin, movepos, EDGE_MOVEDIR );
	}

	return qtrue;
}