Vector CTFBotPayloadGuard::FindVantagePoint(CTFBot *actor, CBaseEntity *target) { CCollectPayloadGuardVantagePoints functor; SearchSurroundingAreas(TheNavMesh->GetNearestNavArea(target), functor, tf_bot_payload_guard_range.GetFloat()); return functor.GetResult(); }
// Do a breadth-first search to find a good retreat spot. // Don't pick a spot that a Player is currently occupying. const Vector *FindNearbyRetreatSpot(CCSBot *me, float maxRange) { CNavArea *area = me->GetLastKnownArea(); if (!area) return nullptr; // collect spots that enemies cannot see CollectRetreatSpotsFunctor collector(me, maxRange); SearchSurroundingAreas(area, &me->pev->origin, collector, maxRange); if (collector.m_count == 0) return nullptr; // select a hiding spot at random int which = RANDOM_LONG(0, collector.m_count - 1); return collector.m_spot[which]; }
/** * 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(); } } }