/**
 * Escape from the bomb.
 */
void EscapeFromBombState::OnUpdate( CCSBot *me )
{
	const Vector *bombPos = me->GetGameState()->GetBombPosition();

	// if we don't know where the bomb is, we shouldn't be in this state
	if (bombPos == NULL)
	{
		me->Idle();
		return;
	}

	// grab our knife to move quickly
	me->EquipKnife();

	// look around
	me->UpdateLookAround();

	if (me->UpdatePathMovement() != CCSBot::PROGRESSING)
	{
		// we have no path, or reached the end of one - create a new path far away from the bomb
		FarAwayFromPositionFunctor func( *bombPos );
		CNavArea *goalArea = FindMinimumCostArea( me->GetLastKnownArea(), func );

		// if this fails, we'll try again next time
		me->ComputePath( goalArea->GetCenter(), FASTEST_ROUTE );
	}
}
Пример #2
0
// Compute shortest path to goal position via A* algorithm
// If 'goalArea' is NULL, path will get as close as it can.
bool CCSBot::ComputePath(CNavArea *goalArea, const Vector *goal, RouteType route)
{
	// Throttle re-pathing
	if (!m_repathTimer.IsElapsed())
		return false;

	// randomize to distribute CPU load
	m_repathTimer.Start(RANDOM_FLOAT(0.4f, 0.6f));

	DestroyPath();

	CNavArea *startArea = m_lastKnownArea;
	if (!startArea)
		return false;

	// note final specific position
	Vector pathEndPosition;

	if (!goal && !goalArea)
		return false;

	if (!goal)
		pathEndPosition = *goalArea->GetCenter();
	else
		pathEndPosition = *goal;

	// make sure path end position is on the ground
	if (goalArea)
		pathEndPosition.z = goalArea->GetZ(&pathEndPosition);
	else
		GetGroundHeight(&pathEndPosition, &pathEndPosition.z);

	// if we are already in the goal area, build trivial path
	if (startArea == goalArea)
	{
		BuildTrivialPath(&pathEndPosition);
		return true;
	}

	// Compute shortest path to goal
	CNavArea *closestArea = nullptr;
	PathCost pathCost(this, route);
	bool pathToGoalExists = NavAreaBuildPath(startArea, goalArea, goal, pathCost, &closestArea);

	CNavArea *effectiveGoalArea = (pathToGoalExists) ? goalArea : closestArea;

	// Build path by following parent links
	// get count
	int count = 0;
	CNavArea *area;
	for (area = effectiveGoalArea; area; area = area->GetParent())
	{
		count++;
	}

	// save room for endpoint
	if (count > MAX_PATH_LENGTH - 1)
		count = MAX_PATH_LENGTH - 1;

	if (count == 0)
		return false;

	if (count == 1)
	{
		BuildTrivialPath(&pathEndPosition);
		return true;
	}

	// build path
	m_pathLength = count;
	for (area = effectiveGoalArea; count && area; area = area->GetParent())
	{
		count--;
		m_path[count].area = area;
		m_path[count].how = area->GetParentHow();
	}

	// compute path positions
	if (ComputePathPositions() == false)
	{
		PrintIfWatched("Error building path\n");
		DestroyPath();
		return false;
	}

	if (!goal)
	{
		switch (m_path[m_pathLength - 1].how)
		{
		case GO_NORTH:
		case GO_SOUTH:
			pathEndPosition.x = m_path[m_pathLength - 1].pos.x;
			pathEndPosition.y = effectiveGoalArea->GetCenter()->y;
			break;

		case GO_EAST:
		case GO_WEST:
			pathEndPosition.x = effectiveGoalArea->GetCenter()->x;
			pathEndPosition.y = m_path[m_pathLength - 1].pos.y;
			break;
		}

		GetGroundHeight(&pathEndPosition, &pathEndPosition.z);
	}

	// append path end position
	m_path[m_pathLength].area = effectiveGoalArea;
	m_path[m_pathLength].pos = pathEndPosition;
	m_path[m_pathLength].ladder = nullptr;
	m_path[m_pathLength].how = NUM_TRAVERSE_TYPES;
	m_pathLength++;

	// do movement setup
	m_pathIndex = 1;
	m_areaEnteredTimestamp = gpGlobals->time;
	m_spotEncounter = nullptr;
	m_goalPosition = m_path[1].pos;

	if (m_path[1].ladder)
		SetupLadderMovement();
	else
		m_pathLadder = nullptr;

	return true;
}
Пример #3
0
/**
 * Follow our leader
 * @todo Clean up this nasty mess
 */
void FollowState::OnUpdate( CDABot *me )
{
	// if we lost our leader, give up
	if (m_leader == NULL || !m_leader->IsAlive())
	{
		me->Idle();
		return;
	}

	// look around
	me->UpdateLookAround();

	// if we are moving, we are not idle
	if (me->IsNotMoving() == false)
		m_idleTimer.Start( RandomFloat( 2.0f, 5.0f ) );

	// compute the leader's speed
	Vector leaderVel = m_leader->GetAbsVelocity();
	float leaderSpeed = Vector2D( leaderVel.x, leaderVel.y ).Length();

	// determine our leader's movement state
	ComputeLeaderMotionState( leaderSpeed );

	// track whether we can see the leader
	bool isLeaderVisible;
	Vector leaderOrigin = GetCentroid( m_leader );
	if (me->IsVisible( leaderOrigin ))
	{
		m_lastSawLeaderTime = gpGlobals->curtime;
		isLeaderVisible = true;
	}
	else
	{
		isLeaderVisible = false;
	}


	// determine whether we should sneak or not
	const float farAwayRange = 750.0f;
	Vector myOrigin = GetCentroid( me );
	if ((leaderOrigin - myOrigin).IsLengthGreaterThan( farAwayRange ))
	{
		// far away from leader - run to catch up
		m_isSneaking = false;
	}
	else if (isLeaderVisible)
	{
		// if we see leader walking and we are nearby, walk
		if (m_leaderMotionState == WALKING)
			m_isSneaking = true;

		// if we are sneaking and our leader starts running, stop sneaking
		if (m_isSneaking && m_leaderMotionState == RUNNING)
			m_isSneaking = false;
	}

	// if we haven't seen the leader for a long time, run
	const float longTime = 20.0f;
	if (gpGlobals->curtime - m_lastSawLeaderTime > longTime)
		m_isSneaking = false;

	if (m_isSneaking)
		me->Walk();
	else
		me->Run();


	bool repath = false;

	// if the leader has stopped, hide nearby
	const float nearLeaderRange = 250.0f;
	if (!me->HasPath() && m_leaderMotionState == STOPPED && m_leaderMotionStateTime.GetElapsedTime() > m_waitTime)
	{
		// throttle how often this check occurs
		m_waitTime += RandomFloat( 1.0f, 3.0f );

		// the leader has stopped - if we are close to him, take up a hiding spot
		if ((leaderOrigin - myOrigin).IsLengthLessThan( nearLeaderRange ))
		{
			const float hideRange = 250.0f;
			if (me->TryToHide( NULL, -1.0f, hideRange, false, USE_NEAREST ))
			{
				me->ResetStuckMonitor();
				return;
			}
		}
	}

	// if we have been idle for awhile, move
	if (m_idleTimer.IsElapsed())
	{
		repath = true;

		// always walk when we move such a short distance
		m_isSneaking = true;
	}

	// if our leader has moved, repath (don't repath if leading is stopping)
	if (leaderSpeed > 100.0f && m_leaderMotionState != STOPPED)
	{
		repath = true;
	}

	// move along our path
	if (me->UpdatePathMovement( NO_SPEED_CHANGE ) != CDABot::PROGRESSING)
	{
		me->DestroyPath();
	}

	// recompute our path if necessary	
	if (repath && m_repathInterval.IsElapsed() && !me->IsOnLadder())
	{
		// recompute our path to keep us near our leader
		m_lastLeaderPos = leaderOrigin;

		me->ResetStuckMonitor();

		const float runSpeed = 200.0f;

		const float collectRange = (leaderSpeed > runSpeed) ? 600.0f : 400.0f;		// 400, 200
		FollowTargetCollector collector( m_leader );
		SearchSurroundingAreas( TheNavMesh->GetNearestNavArea( m_lastLeaderPos ), m_lastLeaderPos, collector, collectRange );

		if (cv_bot_debug.GetBool())
		{
			for( int i=0; i<collector.m_targetAreaCount; ++i )
				collector.m_targetArea[i]->Draw( /*255, 0, 0, 2*/ );		
		}

		// move to one of the collected areas
		if (collector.m_targetAreaCount)
		{
			CNavArea *target = NULL;
			Vector targetPos;

			// if we are idle, pick a random area
			if (m_idleTimer.IsElapsed())
			{
				target = collector.m_targetArea[ RandomInt( 0, collector.m_targetAreaCount-1 ) ];				
				targetPos = target->GetCenter();
				me->PrintIfWatched( "%4.1f: Bored. Repathing to a new nearby area\n", gpGlobals->curtime );
			}
			else
			{
				me->PrintIfWatched( "%4.1f: Repathing to stay with leader.\n", gpGlobals->curtime );

				// find closest area to where we are
				CNavArea *area;
				float closeRangeSq = 9999999999.9f;
				Vector close;

				for( int a=0; a<collector.m_targetAreaCount; ++a )
				{
					area = collector.m_targetArea[a];

					area->GetClosestPointOnArea( myOrigin, &close );

					float rangeSq = (myOrigin - close).LengthSqr();
					if (rangeSq < closeRangeSq)
					{
						target = area;
						targetPos = close;
						closeRangeSq = rangeSq;
					}
				}
			}
						
			if (target == NULL || me->ComputePath( target->GetCenter(), FASTEST_ROUTE ) == NULL)
				me->PrintIfWatched( "Pathfind to leader failed.\n" );

			// throttle how often we repath
			m_repathInterval.Start( 0.5f );

			m_idleTimer.Reset();
		}
	}
}