//-----------------------------------------------------------------------------
// Purpose: Checks if a local route (not using nodes) between vStart
//			and vEnd exists using the moveType
// Input  :
// Output : Returns a route if sucessful or NULL if no local route was possible
//-----------------------------------------------------------------------------
bool CAI_Pathfinder::CheckStaleRoute(const Vector &vStart, const Vector &vEnd, int moveTypes)
{
	// -------------------------------------------------------------------
	// First try to go there directly
	// -------------------------------------------------------------------
	if (moveTypes & bits_CAP_MOVE_GROUND) 
	{
		if (CheckStaleNavTypeRoute( NAV_GROUND, vStart, vEnd ))
			return true;
	}

	// -------------------------------------------------------------------
	// First try to go there directly
	// -------------------------------------------------------------------
	if (moveTypes & bits_CAP_MOVE_FLY) 
	{
		if (CheckStaleNavTypeRoute( NAV_FLY, vStart, vEnd ))
			return true;
	}

	// --------------------------------------------------------------
	//  Try to jump if we can jump to a node
	// --------------------------------------------------------------
	if (moveTypes & bits_CAP_MOVE_JUMP)
	{
		AIMoveTrace_t moveTrace;
		GetOuter()->GetMoveProbe()->MoveLimit( NAV_JUMP, vStart, vEnd, MASK_NPCSOLID, NULL, &moveTrace);
		if (!IsMoveBlocked(moveTrace))
		{
			return true;
		}
		else
		{
			// Can't tell jump up from jump down at this point
			GetOuter()->GetMoveProbe()->MoveLimit( NAV_JUMP, vEnd, vStart, MASK_NPCSOLID, NULL, &moveTrace);
			if (!IsMoveBlocked(moveTrace))
				return true;
		}
	}

	// --------------------------------------------------------------
	//  Try to climb if we can climb to a node
	// --------------------------------------------------------------
	if (moveTypes & bits_CAP_MOVE_CLIMB)
	{
		AIMoveTrace_t moveTrace;
		GetOuter()->GetMoveProbe()->MoveLimit( NAV_CLIMB, vStart, vEnd, MASK_NPCSOLID, NULL, &moveTrace);
		if (!IsMoveBlocked(moveTrace))
		{	
			return true;
		}
	}

	// Man do we suck! Couldn't get there by any route
	return false;
}
Exemple #2
0
void CNPC_Stalker::AddZigZagToPath(void) 
{
	// If already on a detour don't add a zigzag
	if (GetNavigator()->GetCurWaypointFlags() & bits_WP_TO_DETOUR)
	{
		return;
	}

	// If enemy isn't facing me or occluded, don't add a zigzag
	if (HasCondition(COND_ENEMY_OCCLUDED) || !HasCondition ( COND_ENEMY_FACING_ME ))
	{
		return;
	}

	Vector waypointPos = GetNavigator()->GetCurWaypointPos();
	Vector waypointDir = (waypointPos - GetAbsOrigin());

	// If the distance to the next node is greater than ZIG_ZAG_SIZE
	// then add a random zig/zag to the path
	if (waypointDir.LengthSqr() > ZIG_ZAG_SIZE)
	{
		// Pick a random distance for the zigzag (less that sqrt(ZIG_ZAG_SIZE)
		float distance = random->RandomFloat( 30, 60 );

		// Get me a vector orthogonal to the direction of motion
		VectorNormalize( waypointDir );
		Vector vDirUp(0,0,1);
		Vector vDir;
		CrossProduct( waypointDir, vDirUp, vDir);

		// Pick a random direction (left/right) for the zigzag
		if (random->RandomInt(0,1))
		{
			vDir = -1 * vDir;
		}

		// Get zigzag position in direction of target waypoint
		Vector zigZagPos = GetAbsOrigin() + waypointDir * 60;

		// Now offset 
		zigZagPos = zigZagPos + (vDir * distance);

		// Now make sure that we can still get to the zigzag position and the waypoint
		AIMoveTrace_t moveTrace1, moveTrace2;
		GetMoveProbe()->MoveLimit( NAV_GROUND, GetAbsOrigin(), zigZagPos, GetAITraceMask(), NULL, &moveTrace1);
		GetMoveProbe()->MoveLimit( NAV_GROUND, zigZagPos, waypointPos, GetAITraceMask(), NULL, &moveTrace2);
		if ( !IsMoveBlocked( moveTrace1 ) && !IsMoveBlocked( moveTrace2 ) )
		{
			GetNavigator()->PrependWaypoint( zigZagPos, NAV_GROUND, bits_WP_TO_DETOUR );
		}
	}
}
//-----------------------------------------------------------------------------
// Step iteratively toward a destination position
//-----------------------------------------------------------------------------
AIMotorMoveResult_t CAI_Motor::MoveGroundStep( const Vector &newPos, CBaseEntity *pMoveTarget, float yaw, bool bAsFarAsCan, AIMoveTrace_t *pTraceResult )
{
	// By definition, this will produce different results than GroundMoveLimit() 
	// because there's no guarantee that it will step exactly one step 

	// See how far toward the new position we can step...
	// But don't actually test for ground geometric validity;
	// if it isn't valid, there's not much we can do about it
	AIMoveTrace_t moveTrace;
	GetMoveProbe()->TestGroundMove( GetLocalOrigin(), newPos, MASK_NPCSOLID, AITGM_IGNORE_FLOOR, &moveTrace );
	if ( pTraceResult )
	{
		*pTraceResult = moveTrace;
	}

	bool bHitTarget = (moveTrace.pObstruction && (pMoveTarget == moveTrace.pObstruction ));

	// Move forward either if there was no obstruction or if we're told to
	// move as far as we can, regardless
	bool bIsBlocked = IsMoveBlocked(moveTrace.fStatus);
	if ( !bIsBlocked || bAsFarAsCan || bHitTarget )
	{
		// The true argument here causes it to touch all triggers
		// in the volume swept from the previous position to the current position
		UTIL_SetOrigin(GetOuter(), moveTrace.vEndPosition, true);
		
		// skip tiny steps, but notify the shadow object of any large steps
		if ( moveTrace.flStepUpDistance > 0.1f )
		{
			float height = clamp( moveTrace.flStepUpDistance, 0, StepHeight() );
			IPhysicsObject *pPhysicsObject = GetOuter()->VPhysicsGetObject();
			if ( pPhysicsObject )
			{
				IPhysicsShadowController *pShadow = pPhysicsObject->GetShadowController();
				if ( pShadow )
				{
					pShadow->StepUp( height );
				}
			}
		}
		if ( yaw != -1 )
		{
			QAngle angles = GetLocalAngles();
			angles.y = yaw;
			SetLocalAngles( angles );
		}
		if ( bHitTarget )
			return AIM_PARTIAL_HIT_TARGET;
			
		if ( !bIsBlocked )
			return AIM_SUCCESS;
			
		if ( moveTrace.fStatus == AIMR_BLOCKED_NPC )
			return AIM_PARTIAL_HIT_NPC;

		return AIM_PARTIAL_HIT_WORLD;
	}
	return AIM_FAILED;
}
//-----------------------------------------------------------------------------
// Purpose: Handles movement towards the last move target.
// Input  : flInterval - 
//-----------------------------------------------------------------------------
bool CNPC_Controller::OverridePathMove( float flInterval )
{
	CBaseEntity *pMoveTarget = (GetTarget()) ? GetTarget() : GetEnemy();
	Vector waypointDir = GetNavigator()->GetCurWaypointPos() - GetLocalOrigin();

	float flWaypointDist = waypointDir.Length2D();
	VectorNormalize(waypointDir);

	// cut corner?
	if (flWaypointDist < 128)
	{
		if (m_flGroundSpeed > 100)
			m_flGroundSpeed -= 40;
	}
	else
	{
		if (m_flGroundSpeed < 400)
			m_flGroundSpeed += 10;
	}

	m_velocity = m_velocity * 0.8 + m_flGroundSpeed * waypointDir * 0.5;
	SetAbsVelocity( m_velocity );

	// -----------------------------------------------------------------
	// Check route is blocked
	// ------------------------------------------------------------------
	Vector checkPos = GetLocalOrigin() + (waypointDir * (m_flGroundSpeed * flInterval));

	AIMoveTrace_t moveTrace;
	GetMoveProbe()->MoveLimit( NAV_FLY, GetLocalOrigin(), checkPos, MASK_NPCSOLID|CONTENTS_WATER,
		pMoveTarget, &moveTrace);
	if (IsMoveBlocked( moveTrace ))
	{
		TaskFail(FAIL_NO_ROUTE);
		GetNavigator()->ClearGoal();
		return true;
	}

	// ----------------------------------------------
	
	Vector lastPatrolDir = GetNavigator()->GetCurWaypointPos() - GetLocalOrigin();
	
	if ( ProgressFlyPath( flInterval, pMoveTarget, MASK_NPCSOLID, false, 64 ) == AINPP_COMPLETE )
	{
		{
			m_vLastPatrolDir = lastPatrolDir;
			VectorNormalize(m_vLastPatrolDir);
		}
		return true;
	}
	return false;
}
// make this alien jump off the head of the ent he's standing on
bool CASW_Alien_Jumper::DoJumpOffHead()
{
	//Too soon to try to jump
	if ( m_flJumpTime > gpGlobals->curtime )
		return false;

	if (!(GetGroundEntity()) || GetNavType() == NAV_JUMP )
		return false;

	// force this drone to have jumping capabilities
	m_bDisableJump = false;
	CapabilitiesAdd( bits_CAP_MOVE_JUMP );

	//Vector vecDest = RandomVector(-1, 1);
	//vecDest.z = 0;
	//vecDest *= random->RandomFloat(30, 100);
	Vector vecDest;
	AngleVectors(GetAbsAngles(), &vecDest);
	vecDest *= 200.0f;
	vecDest += GetAbsOrigin();

	// Try the jump
	AIMoveTrace_t moveTrace;
	GetMoveProbe()->MoveLimit( NAV_JUMP, GetAbsOrigin(), vecDest, MASK_NPCSOLID, NULL, &moveTrace );

	//See if it succeeded
	if ( IsMoveBlocked( moveTrace.fStatus ) )
	{
		if ( asw_debug_aliens.GetInt() == 2 )
		{
			NDebugOverlay::Box( vecDest, GetHullMins(), GetHullMaxs(), 255, 0, 0, 0, 5 );
			NDebugOverlay::Line( GetAbsOrigin(), vecDest, 255, 0, 0, 0, 5 );
		}

		m_flJumpTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 2.0f );
		return false;
	}

	if ( asw_debug_aliens.GetInt() == 2 )
	{
		NDebugOverlay::Box( vecDest, GetHullMins(), GetHullMaxs(), 0, 255, 0, 0, 5 );
		NDebugOverlay::Line( GetAbsOrigin(), vecDest, 0, 255, 0, 0, 5 );
	}

	//Save this jump in case the next time fails	
	m_vecSavedJump = moveTrace.vJumpVelocity;
	m_vecLastJumpAttempt = vecDest;
	SetSchedule(SCHED_ASW_ALIEN_JUMP);
	m_bForcedStuckJump = true;

	return true;
}
AIMotorMoveResult_t CAI_Motor::MoveFlyExecute( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult )
{
	// turn in the direction of movement
	MoveFacing( move );

	// calc accel/decel rates
	float flNewSpeed = GetIdealSpeed();
	SetMoveVel( move.dir * flNewSpeed );

	float flTotal = 0.5 * (GetCurSpeed() + flNewSpeed) * GetMoveInterval();

	float distance = move.maxDist;

	// can I move farther in this interval than I'm supposed to?
	if (flTotal > distance)
	{
		// only use a portion of the time interval
		SetMoveInterval( GetMoveInterval() * (1 - distance / flTotal) );
		flTotal = distance;
	}
	else
	{
		// use all the time
		SetMoveInterval( 0 );
	}

	Vector vecStart, vecEnd;
	vecStart = GetLocalOrigin();
	VectorMA( vecStart, flTotal, move.dir, vecEnd );

	AIMoveTrace_t moveTrace;
	GetMoveProbe()->MoveLimit( NAV_FLY, vecStart, vecEnd, MASK_NPCSOLID, NULL, &moveTrace );
	if ( pTraceResult )
		*pTraceResult = moveTrace;
	
	// Check for total blockage
	if (fabs(moveTrace.flDistObstructed - flTotal) <= 1e-1)
	{
		// But if we bumped into our target, then we succeeded!
		if ( move.pMoveTarget && (moveTrace.pObstruction == move.pMoveTarget) )
			return AIM_PARTIAL_HIT_TARGET;

		return AIM_FAILED;
	}

	// The true argument here causes it to touch all triggers
	// in the volume swept from the previous position to the current position
	UTIL_SetOrigin(GetOuter(), moveTrace.vEndPosition, true);

	return (IsMoveBlocked(moveTrace.fStatus)) ? AIM_PARTIAL_HIT_WORLD : AIM_SUCCESS;
}
bool CZombie::OnObstructingDoor( AILocalMoveGoal_t *pMoveGoal, CBaseDoor *pDoor, float distClear, AIMoveResult_t *pResult )
{
	if ( BaseClass::OnObstructingDoor( pMoveGoal, pDoor, distClear, pResult ) )
	{
		if  ( IsMoveBlocked( *pResult ) && pMoveGoal->directTrace.vHitNormal != vec3_origin )
		{
			m_hBlockingDoor = pDoor;
			m_flDoorBashYaw = UTIL_VecToYaw( pMoveGoal->directTrace.vHitNormal * -1 );	
		}
		return true;
	}

	return false;
}
//-----------------------------------------------------------------------------
// Checks a stale navtype route 
//-----------------------------------------------------------------------------
bool CAI_Pathfinder::CheckStaleNavTypeRoute( Navigation_t navType, const Vector &vStart, const Vector &vEnd )
{
	AIMoveTrace_t moveTrace;
	GetOuter()->GetMoveProbe()->MoveLimit( navType, vStart, vEnd, MASK_NPCSOLID, NULL, 100, AIMLF_IGNORE_TRANSIENTS, &moveTrace);

	// Is the direct route clear?
	if (!IsMoveBlocked(moveTrace))
	{
		return true;
	}

	// Next try to triangulate
	// FIXME: Since blocked dist is an unreliable number, this computation is bogus
	Vector vecDelta;
	VectorSubtract( vEnd, vStart, vecDelta );
	float flTotalDist = vecDelta.Length();

	Vector vApex;
	if (Triangulate( navType, vStart, vEnd, flTotalDist - moveTrace.flDistObstructed, NULL, &vApex ))
	{
		return true;
	}

	CEntity *cent = CEntity::Instance(moveTrace.pObstruction);
	// Try a giveway request, if I can get there ignoring NPCs
	if ( cent && cent->MyNPCPointer() )
	{
		GetOuter()->GetMoveProbe()->MoveLimit( navType, vStart, vEnd, MASK_NPCSOLID_BRUSHONLY, NULL, &moveTrace);

		if (!IsMoveBlocked(moveTrace))
		{
			return true;
		}
	}

	return false;
}
bool CASW_Alien_Jumper::DoJumpTo(Vector &vecDest)
{	
	//Too soon to try to jump
	if ( m_flJumpTime > gpGlobals->curtime )
		return false;

	// only jump if you're on the ground
  	if (!(GetFlags() & FL_ONGROUND) || GetNavType() == NAV_JUMP )
		return false;

	// Don't jump if I'm not allowed
	if ( ( CapabilitiesGet() & bits_CAP_MOVE_JUMP ) == false )
		return false;

	// Try the jump
	AIMoveTrace_t moveTrace;
	GetMoveProbe()->MoveLimit( NAV_JUMP, GetAbsOrigin(), vecDest, MASK_NPCSOLID, NULL, &moveTrace );

	//See if it succeeded
	if ( IsMoveBlocked( moveTrace.fStatus ) )
	{
		if ( asw_debug_aliens.GetInt() == 2 )
		{
			NDebugOverlay::Box( vecDest, GetHullMins(), GetHullMaxs(), 255, 0, 0, 0, 5 );
			NDebugOverlay::Line( GetAbsOrigin(), vecDest, 255, 0, 0, 0, 5 );
		}

		m_flJumpTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 2.0f );
		return false;
	}

	if ( asw_debug_aliens.GetInt() == 2 )
	{
		NDebugOverlay::Box( vecDest, GetHullMins(), GetHullMaxs(), 0, 255, 0, 0, 5 );
		NDebugOverlay::Line( GetAbsOrigin(), vecDest, 0, 255, 0, 0, 5 );
	}

	//Save this jump in case the next time fails	
	m_vecSavedJump = moveTrace.vJumpVelocity;
	m_vecLastJumpAttempt = vecDest;
	SetSchedule(SCHED_ASW_ALIEN_JUMP);
	m_bForcedStuckJump = true;

	//Msg("Drone saving jump vec %f %f %f\n", m_vecSavedJump.x, m_vecSavedJump.y, m_vecSavedJump.z);

	return true;
}
bool CAI_PlaneSolver::Solve( const AILocalMoveGoal_t &goal, float distClear, Vector *pSolution )
{
	bool solved = false;
	
	//---------------------------------
	
	if ( goal.speed == 0 )
		return false;

	if ( DetectUnsolvable( goal ) )
		return false;

	//---------------------------------

	bool fVeryClose			 = ( distClear < 1.0 );
	float degreesPositiveArc = ( !fVeryClose ) ? DEGREES_POSITIVE_ARC : DEGREES_POSITIVE_ARC_CLOSE_OBSTRUCTION;
	float probeDist			 = CalcProbeDist( goal.speed );
	
	if ( goal.flags & ( AILMG_TARGET_IS_TRANSITION | AILMG_TARGET_IS_GOAL ) )
	{
		probeDist = min( goal.maxDist, probeDist );
	}

	if ( GenerateObstacleSuggestions( goal, goal.directTrace, distClear, probeDist, degreesPositiveArc, NUM_PROBES ) != SR_FAIL )
	{
		if ( RunMoveSolver( goal, goal.directTrace, degreesPositiveArc, !fVeryClose, pSolution ) )
		{
			// Visualize desired + actual directions
			VisualizeSolution( goal.dir, *pSolution );

			AIMoveTrace_t moveTrace;
			float 		  requiredMovement = goal.speed * GetMotor()->GetMoveInterval();

			MoveLimit( goal.navType, GetLocalOrigin() + *pSolution * requiredMovement, false, true, &moveTrace );
			
			if ( !IsMoveBlocked( moveTrace ) )
				solved = true;
			else
				solved = false;
		}
	}

	m_fSolvedPrev 		= ( solved && goal.speed != 0 ); // a solution found when speed is zero is not meaningful
	m_PrevTarget 		= goal.target;

	return solved;
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CHL1NPCTalker::OnObstructingDoor( AILocalMoveGoal_t *pMoveGoal, CBaseDoor *pDoor, float distClear, AIMoveResult_t *pResult )
{
	// If we can't get through the door, try and open it
	if ( BaseClass::OnObstructingDoor( pMoveGoal, pDoor, distClear, pResult ) )
	{
		if  ( IsMoveBlocked( *pResult ) && pMoveGoal->directTrace.vHitNormal != vec3_origin )
		{
			// Can't do anything if the door's locked
			if ( !pDoor->m_bLocked && !pDoor->HasSpawnFlags(SF_DOOR_NONPCS) )
			{
				// Tell the door to open
				variant_t emptyVariant;
				pDoor->AcceptInput( "Open", this, this, emptyVariant, USE_TOGGLE );
				*pResult = AIMR_OK;
			}
		}
		return true;
	}

	return false;
}
AIMoveResult_t CAI_LocalNavigator::MoveCalcRaw( AILocalMoveGoal_t *pMoveGoal, bool bOnlyCurThink )
{
	AI_PROFILE_SCOPE(CAI_Motor_MoveCalc);
	
	AIMoveResult_t result = AIMR_OK; // Assume success
	AIMoveTrace_t  directTrace;
	float	   	   distClear;
	
	// --------------------------------------------------

	bool bDirectClear = MoveCalcDirect( pMoveGoal, bOnlyCurThink, &distClear, &result);
	if ( OnCalcBaseMove( pMoveGoal, distClear, &result ) )
	{
		SetSolveCookie();
		return DbgResult( result );
	}

	bool bShouldSteer = ( !(pMoveGoal->flags & AILMG_NO_STEER) && ( !bDirectClear || HaveObstacles() ) );

	if ( bDirectClear && !bShouldSteer )
	{
		SetSolveCookie();
		return DbgResult( result );
	}
	
	// --------------------------------------------------

	if ( bShouldSteer )
	{
		if ( !bDirectClear )
		{
			if ( OnObstructionPreSteer( pMoveGoal, distClear, &result ) )
			{
				SetSolveCookie();
				return DbgResult( result );
			}
		}

		if ( MoveCalcSteer( pMoveGoal, distClear, &result ) )
		{
			SetSolveCookie();
			return DbgResult( result );			
		}
	}

	if ( OnFailedSteer( pMoveGoal, distClear, &result ) )
	{
		SetSolveCookie();
		return DbgResult( result );
	}

	// --------------------------------------------------
	
	if ( OnFailedLocalNavigation( pMoveGoal, distClear, &result ) )
	{
		SetSolveCookie();
		return DbgResult( result );
	}

	if ( distClear < GetOuter()->GetMotor()->MinStoppingDist() )
	{
		if ( OnInsufficientStopDist( pMoveGoal, distClear, &result ) )
		{
			SetSolveCookie();
			return DbgResult( result );
		}

		if ( MoveCalcStop( pMoveGoal, distClear, &result) )
		{
			SetSolveCookie();
			return DbgResult( result );
		}
	}

	// A hopeful result... may get in trouble at next waypoint and obstruction is still there
	if ( distClear > pMoveGoal->curExpectedDist )
	{
		SetSolveCookie();
		return DbgResult( AIMR_OK );
	}

	// --------------------------------------------------

	DebugNoteMovementFailure();
	SetSolveCookie();
	return DbgResult( IsMoveBlocked( pMoveGoal->directTrace.fStatus ) ? pMoveGoal->directTrace.fStatus : AIMR_ILLEGAL );
}
//-----------------------------------------------------------------------------
// Purpose: 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CASW_Alien_Jumper::ShouldJump( void )
{
	if ( GetEnemy() == NULL )
		return false;

	// don't jump if we're stunned
	if (m_bElectroStunned)
		return false;

	//Too soon to try to jump
	if ( m_flJumpTime > gpGlobals->curtime )
		return false;

	// only jump if you're on the ground
  	if (!(GetFlags() & FL_ONGROUND) || GetNavType() == NAV_JUMP )
		return false;

	// Don't jump if I'm not allowed
	if ( ( CapabilitiesGet() & bits_CAP_MOVE_JUMP ) == false )
		return false;

	Vector vEnemyForward, vForward;

	GetEnemy()->GetVectors( &vEnemyForward, NULL, NULL );
	GetVectors( &vForward, NULL, NULL );

	float flDot = DotProduct( vForward, vEnemyForward );

	if ( flDot < 0.5f )
		 flDot = 0.5f;

	Vector vecPredictedPos;

	//Get our likely position in two seconds
	UTIL_PredictedPosition( GetEnemy(), flDot * 2.5f, &vecPredictedPos );

	// Don't jump if we're already near the target
	if ( ( GetAbsOrigin() - vecPredictedPos ).LengthSqr() < (512*512) )
		return false;

	//Don't retest if the target hasn't moved enough
	//FIXME: Check your own distance from last attempt as well
	if ( ( ( m_vecLastJumpAttempt - vecPredictedPos ).LengthSqr() ) < (128*128) )
	{
		m_flJumpTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 2.0f );		
		return false;
	}

	Vector	targetDir = ( vecPredictedPos - GetAbsOrigin() );

	float flDist = VectorNormalize( targetDir );

	// don't jump at target it it's very close
	if (flDist < ANTLION_JUMP_MIN)
		return false;

	Vector	targetPos = vecPredictedPos + ( targetDir * (GetHullWidth()*4.0f) );

	// Try the jump
	AIMoveTrace_t moveTrace;
	GetMoveProbe()->MoveLimit( NAV_JUMP, GetAbsOrigin(), targetPos, MASK_NPCSOLID, GetNavTargetEntity(), &moveTrace );

	//See if it succeeded
	if ( IsMoveBlocked( moveTrace.fStatus ) )
	{
		if ( asw_debug_aliens.GetInt() == 2 )
		{
			NDebugOverlay::Box( targetPos, GetHullMins(), GetHullMaxs(), 255, 0, 0, 0, 5 );
			NDebugOverlay::Line( GetAbsOrigin(), targetPos, 255, 0, 0, 0, 5 );
		}

		m_flJumpTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 2.0f );
		return false;
	}

	if ( asw_debug_aliens.GetInt() == 2 )
	{
		NDebugOverlay::Box( targetPos, GetHullMins(), GetHullMaxs(), 0, 255, 0, 0, 5 );
		NDebugOverlay::Line( GetAbsOrigin(), targetPos, 0, 255, 0, 0, 5 );
	}

	//Save this jump in case the next time fails
	m_vecSavedJump = moveTrace.vJumpVelocity;
	m_vecLastJumpAttempt = targetPos;

	return true;
}
Exemple #14
0
//-----------------------------------------------------------------------------
// Step iteratively toward a destination position
//-----------------------------------------------------------------------------
AIMotorMoveResult_t CAI_Motor::MoveGroundStep( const Vector &newPos, CBaseEntity *pMoveTarget, float yaw, bool bAsFarAsCan, bool bTestZ, AIMoveTrace_t *pTraceResult )
{
	// By definition, this will produce different results than GroundMoveLimit() 
	// because there's no guarantee that it will step exactly one step 

	// See how far toward the new position we can step...
	// But don't actually test for ground geometric validity;
	// if it isn't valid, there's not much we can do about it
	AIMoveTrace_t moveTrace;
	unsigned testFlags = AITGM_IGNORE_FLOOR;

	char *pchHackBoolToInt = (char*)(&bTestZ);
	if ( *pchHackBoolToInt == 2 )
	{
		testFlags |= AITGM_CRAWL_LARGE_STEPS;
	}
	else
	{
		if ( !bTestZ )
			testFlags |= AITGM_2D;
	}

#ifdef DEBUG
	if ( ai_draw_motor_movement.GetBool() )
		testFlags |= AITGM_DRAW_RESULTS;
#endif

	GetMoveProbe()->TestGroundMove( GetLocalOrigin(), newPos, GetOuter()->GetAITraceMask(), testFlags, &moveTrace );
	if ( pTraceResult )
	{
		*pTraceResult = moveTrace;
	}

	bool bHitTarget = (moveTrace.pObstruction && (pMoveTarget == moveTrace.pObstruction ));

	// Move forward either if there was no obstruction or if we're told to
	// move as far as we can, regardless
	bool bIsBlocked = IsMoveBlocked(moveTrace.fStatus);
	if ( !bIsBlocked || bAsFarAsCan || bHitTarget )
	{
#ifdef DEBUG
		if ( GetMoveProbe()->CheckStandPosition( GetLocalOrigin(), GetOuter()->GetAITraceMask() ) && !GetMoveProbe()->CheckStandPosition( moveTrace.vEndPosition, GetOuter()->GetAITraceMask() ) )
		{
			DevMsg( 2, "Warning: AI motor probably given invalid instructions\n" );
		}
#endif

		// The true argument here causes it to touch all triggers
		// in the volume swept from the previous position to the current position
		UTIL_SetOrigin(GetOuter(), moveTrace.vEndPosition, true);

		// check to see if our ground entity has changed
		// NOTE: This is to detect changes in ground entity as the movement code has optimized out
		// ground checks.  So now we have to do a simple recheck to make sure we detect when we've 
		// stepped onto a new entity.
		if ( GetOuter()->GetFlags() & FL_ONGROUND )
		{
			GetOuter()->PhysicsStepRecheckGround();
		}

		// skip tiny steps, but notify the shadow object of any large steps
		if ( moveTrace.flStepUpDistance > 0.1f )
		{
			float height = clamp( moveTrace.flStepUpDistance, 0, StepHeight() );
			IPhysicsObject *pPhysicsObject = GetOuter()->VPhysicsGetObject();
			if ( pPhysicsObject )
			{
				IPhysicsShadowController *pShadow = pPhysicsObject->GetShadowController();
				if ( pShadow )
				{
					pShadow->StepUp( height );
				}
			}
		}
		if ( yaw != -1 )
		{
			QAngle angles = GetLocalAngles();
			angles.y = yaw;
			SetLocalAngles( angles );
		}
		if ( bHitTarget )
			return AIM_PARTIAL_HIT_TARGET;
			
		if ( !bIsBlocked )
			return AIM_SUCCESS;
			
		if ( moveTrace.fStatus == AIMR_BLOCKED_NPC )
			return AIM_PARTIAL_HIT_NPC;

		return AIM_PARTIAL_HIT_WORLD;
	}
	return AIM_FAILED;
}
bool CAI_Pathfinder::Triangulate( Navigation_t navType, const Vector &vecStart, const Vector &vecEndIn, 
	float flDistToBlocker, const CEntity *pTargetEnt, Vector *pApex )
{
	if ( GetOuter()->IsFlaggedEfficient() )
		return false;

	Assert( pApex );

	Vector vecForward, vecUp, vecPerpendicular;
	VectorSubtract( vecEndIn, vecStart, vecForward );
	float flTotalDist = VectorNormalize( vecForward );

	Vector vecEnd;

	// If we're walking, then don't try to triangulate over large distances
	if ( navType != NAV_FLY && flTotalDist > MAX_TRIAGULATION_DIST)
	{
		vecEnd = vecForward * MAX_TRIAGULATION_DIST;
		flTotalDist = MAX_TRIAGULATION_DIST;
		if ( !GetOuter()->GetMoveProbe()->MoveLimit(navType, vecEnd, vecEndIn, MASK_NPCSOLID, pTargetEnt) )
		{
			return false;
		}

	}
	else
		vecEnd = vecEndIn;

	// Compute a direction vector perpendicular to the desired motion direction
	if ( 1.0f - fabs(vecForward.z) > 1e-3 )
	{
		vecUp.Init( 0, 0, 1 );
		CrossProduct( vecForward, vecUp, vecPerpendicular );	// Orthogonal to facing
	}
	else
	{
		vecUp.Init( 0, 1, 0 );
		vecPerpendicular.Init( 1, 0, 0 ); 
	}

	// Grab the size of the navigation bounding box
	float sizeX = 0.5f * NAI_Hull::Length(GetHullType());
	float sizeZ = 0.5f * NAI_Hull::Height(GetHullType());

	// start checking right about where the object is, picking two equidistant
	// starting points, one on the left, one on the right. As we progress 
	// through the loop, we'll push these away from the obstacle, hoping to 
	// find a way around on either side. m_vecSize.x is added to the ApexDist 
	// in order to help select an apex point that insures that the NPC is 
	// sufficiently past the obstacle before trying to turn back onto its original course.


	float flApexDist = flDistToBlocker + sizeX;
	if (flApexDist > flTotalDist) 
	{
		flApexDist = flTotalDist;
	}

	// Compute triangulation apex points (NAV_FLY attempts vertical triangulation too)
	Vector vecDelta[2];
	Vector vecApex[4];
	float pApexDist[4];

	Vector vecCenter;
	int nNumToTest = 2;
	VectorMultiply( vecPerpendicular, sizeX, vecDelta[0] );

	VectorMA( vecStart, flApexDist, vecForward, vecCenter );
	VectorSubtract( vecCenter, vecDelta[0], vecApex[0] );
	VectorAdd( vecCenter, vecDelta[0], vecApex[1] );
 	vecDelta[0] *= 2.0f;
	pApexDist[0] = pApexDist[1] = flApexDist;

	if (navType == NAV_FLY)
	{
		VectorMultiply( vecUp, 3.0f * sizeZ, vecDelta[1] );
		VectorSubtract( vecCenter, vecDelta[1], vecApex[2] );
		VectorAdd( vecCenter, vecDelta[1], vecApex[3] );
		pApexDist[2] = pApexDist[3] = flApexDist;
		nNumToTest = 4;
	}

	AIMoveTrace_t moveTrace;
	for (int i = 0; i < 2; ++i )
	{
		// NOTE: Do reverse order so fliers try to move over the top first 
		for (int j = nNumToTest; --j >= 0; )
		{
			if (TestTriangulationRoute(navType, vecStart, vecApex[j], vecEnd, pTargetEnt, &moveTrace))
			{
				*pApex  = vecApex[j];
				return true;
			}

			// Here, the starting half of the triangle was blocked. Lets
			// pull back the apex toward the start...
			if (IsMoveBlocked(moveTrace))
			{
				Vector vecStartToObstruction;
				VectorSubtract( moveTrace.vEndPosition, vecStart, vecStartToObstruction );
				float flDistToObstruction = DotProduct( vecStartToObstruction, vecForward );

				float flNewApexDist = pApexDist[j];
				if (pApexDist[j] > flDistToObstruction)
					flNewApexDist = flDistToObstruction;

				VectorMA( vecApex[j], flNewApexDist - pApexDist[j], vecForward, vecApex[j] );
				pApexDist[j] = flNewApexDist;
			}

			// NOTE: This has to occur *after* the code above because
			// the above code uses vecApex for some distance computations
			if (j & 0x1)
				vecApex[j] += vecDelta[j >> 1];
			else
				vecApex[j] -= vecDelta[j >> 1];
		}
	}
AIMotorMoveResult_t CAI_BlendedMotor::MoveFlyExecute( const AILocalMoveGoal_t &move, AIMoveTrace_t *pTraceResult )
{
	if ( move.curExpectedDist < 0.001 )
		return BaseClass::MoveFlyExecute( move, pTraceResult );

	BuildMoveScript( move, pTraceResult );

	float flNewSpeed = GetCurSpeed();
	float flTotalDist = GetMoveScriptDist( flNewSpeed );

	Assert( move.maxDist < 0.01 || flTotalDist > 0.0 );

	// --------------------------------------------
	// turn in the direction of movement
	// --------------------------------------------
	
	float flNewYaw = GetMoveScriptYaw( );

	// get facing based on movement yaw
	AILocalMoveGoal_t move2 = move;
	move2.facing = UTIL_YawToVector( flNewYaw );

	// turn in the direction needed
	MoveFacing( move2 );

	GetOuter()->m_flGroundSpeed = GetSequenceGroundSpeed( GetSequence());

	SetMoveScriptAnim( flNewSpeed );

	// DevMsg( "%6.2f : Speed %.1f : %.1f\n", gpGlobals->curtime, flNewSpeed, GetIdealSpeed() );

	// reset actual "sequence" ground speed based current movement sequence, orientation

	// FIXME: the above is redundant with MoveGroundExecute, and the below is a mix of MoveGroundExecuteWalk and MoveFlyExecute

	bool bReachingLocalGoal = ( flTotalDist > move.maxDist );

	// can I move farther in this interval than I'm supposed to?
	if ( bReachingLocalGoal )
	{
		if ( !(move.flags & AILMG_CONSUME_INTERVAL) )
		{
			// only use a portion of the time interval
			SetMoveInterval( GetMoveInterval() * (1 - move.maxDist / flTotalDist) );
		}
		else
			SetMoveInterval( 0 );
		flTotalDist = move.maxDist;
	}
	else
	{
		// use all the time
		SetMoveInterval( 0 );
	}

	SetMoveVel( move.dir * flNewSpeed );

	// orig
	Vector vecStart, vecEnd;
	vecStart = GetLocalOrigin();
	VectorMA( vecStart, flTotalDist, move.dir, vecEnd );

	AIMoveTrace_t moveTrace;
	GetMoveProbe()->MoveLimit( NAV_FLY, vecStart, vecEnd, MASK_NPCSOLID, NULL, &moveTrace );
	if ( pTraceResult )
		*pTraceResult = moveTrace;
	
	// Check for total blockage
	if (fabs(moveTrace.flDistObstructed - flTotalDist) <= 1e-1)
	{
		// But if we bumped into our target, then we succeeded!
		if ( move.pMoveTarget && (moveTrace.pObstruction == move.pMoveTarget) )
			return AIM_PARTIAL_HIT_TARGET;

		return AIM_FAILED;
	}

	// The true argument here causes it to touch all triggers
	// in the volume swept from the previous position to the current position
	UTIL_SetOrigin(GetOuter(), moveTrace.vEndPosition, true);

	return (IsMoveBlocked(moveTrace.fStatus)) ? AIM_PARTIAL_HIT_WORLD : AIM_SUCCESS;
}
Exemple #17
0
//-----------------------------------------------------------------------------
// Purpose: Handles all flight movement.
// Input  : flInterval - Seconds to simulate.
//-----------------------------------------------------------------------------
void CNPC_Crow::MoveCrowFly( float flInterval )
{
	//
	// Bound interval so we don't get ludicrous motion when debugging
	// or when framerate drops catastrophically.  
	//
	if (flInterval > 1.0)
	{
		flInterval = 1.0;
	}

	m_flDangerSoundTime = gpGlobals->curtime + 5.0f;

	//
	// Determine the goal of our movement.
	//
	Vector vecMoveGoal = GetAbsOrigin();

	if ( GetNavigator()->IsGoalActive() )
	{
		vecMoveGoal = GetNavigator()->GetCurWaypointPos();

		if ( GetNavigator()->CurWaypointIsGoal() == false  )
		{
  			AI_ProgressFlyPathParams_t params( MASK_NPCSOLID );
			params.bTrySimplify = false;

			GetNavigator()->ProgressFlyPath( params ); // ignore result, crow handles completion directly

			// Fly towards the hint.
			if ( GetNavigator()->GetPath()->GetCurWaypoint() )
			{
				vecMoveGoal = GetNavigator()->GetCurWaypointPos();
			}
		}
	}
	else
	{
		// No movement goal.
		vecMoveGoal = GetAbsOrigin();
		SetAbsVelocity( vec3_origin );
		return;
	}

	Vector vecMoveDir = ( vecMoveGoal - GetAbsOrigin() );
	Vector vForward;
	AngleVectors( GetAbsAngles(), &vForward );
	
	//
	// Fly towards the movement goal.
	//
	float flDistance = ( vecMoveGoal - GetAbsOrigin() ).Length();

	if ( vecMoveGoal != m_vDesiredTarget )
	{
		m_vDesiredTarget = vecMoveGoal;
	}
	else
	{
		m_vCurrentTarget = ( m_vDesiredTarget - GetAbsOrigin() );
		VectorNormalize( m_vCurrentTarget );
	}

	float flLerpMod = 0.25f;

	if ( flDistance <= 256.0f )
	{
		flLerpMod = 1.0f - ( flDistance / 256.0f );
	}


	VectorLerp( vForward, m_vCurrentTarget, flLerpMod, vForward );


	if ( flDistance < CROW_AIRSPEED * flInterval )
	{
		if ( GetNavigator()->IsGoalActive() )
		{
			if ( GetNavigator()->CurWaypointIsGoal() )
			{
				m_bReachedMoveGoal = true;
			}
			else
			{
				GetNavigator()->AdvancePath();
			}
		}
		else
			m_bReachedMoveGoal = true;
	}

	if ( GetHintNode() )
	{
		AIMoveTrace_t moveTrace;
		GetMoveProbe()->MoveLimit( NAV_FLY, GetAbsOrigin(), GetNavigator()->GetCurWaypointPos(), MASK_NPCSOLID, GetNavTargetEntity(), &moveTrace );

		//See if it succeeded
		if ( IsMoveBlocked( moveTrace.fStatus ) )
		{
			Vector vNodePos = vecMoveGoal;
			GetHintNode()->GetPosition(this, &vNodePos);
			
			GetNavigator()->SetGoal( vNodePos );
		}
	}

	//
	// Look to see if we are going to hit anything.
	//
	VectorNormalize( vForward );
	Vector vecDeflect;
	if ( Probe( vForward, CROW_AIRSPEED * flInterval, vecDeflect ) )
	{
		vForward = vecDeflect;
		VectorNormalize( vForward );
	}

	SetAbsVelocity( vForward * CROW_AIRSPEED );

	if ( GetAbsVelocity().Length() > 0 && GetNavigator()->CurWaypointIsGoal() && flDistance < CROW_AIRSPEED )
	{
		SetIdealActivity( (Activity)ACT_CROW_LAND );
	}


	//Bank and set angles.
	Vector vRight;
	QAngle vRollAngle;
	
	VectorAngles( vForward, vRollAngle );
	vRollAngle.z = 0;

	AngleVectors( vRollAngle, NULL, &vRight, NULL );

	float flRoll = DotProduct( vRight, vecMoveDir ) * 45;
	flRoll = clamp( flRoll, -45, 45 );

	vRollAngle[ROLL] = flRoll;
	SetAbsAngles( vRollAngle );
}