void CHostageImprov::FaceOutwards() { TraceResult result; Vector to; float farthestRange = 0.0f; int farthest = 0; static Vector corner[] = { Vector(-1000, 1000, 0), Vector(1000, 1000, 0), Vector(-1000, -1000, 0), Vector(1000, -1000, 0) }; const int cornerCount = ARRAYSIZE(corner); for (int i = 0; i < cornerCount; ++i) { to = GetCentroid() + corner[i]; UTIL_TraceLine(GetCentroid(), to, ignore_monsters, ignore_glass, m_hostage->edict(), &result); float_precision range = (result.vecEndPos - GetCentroid()).LengthSquared(); if (range > farthestRange) { farthestRange = range; farthest = i; } } to = GetCentroid() + corner[farthest]; FaceTo(to); }
/** * Return the closest active player on the given team to the given position. * If 'distance' is non-NULL, the distance to the closest player is returned in it. */ extern CBasePlayer *UTIL_GetClosestPlayer( const Vector &pos, int team, float *distance ) { CBasePlayer *closePlayer = NULL; float closeDistSq = 999999999999.9f; for ( int i = 1; i <= gpGlobals->maxClients; ++i ) { CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) ); if (!IsEntityValid( player )) continue; if (!player->IsAlive()) continue; if (player->GetTeamNumber() != team) continue; Vector playerOrigin = GetCentroid( player ); float distSq = (playerOrigin - pos).LengthSqr(); if (distSq < closeDistSq) { closeDistSq = distSq; closePlayer = static_cast<CBasePlayer *>( player ); } } if (distance) *distance = (float)sqrt( closeDistSq ); return closePlayer; }
void QueryClusterer::MergeClusters() { // Merge two clusters that are within the threshold in similarity // Iterate from left to right and merge the left one into right one and mark // the left one for deletion std::vector<Cluster *> to_delete; for (auto i = clusters_.begin(); i != clusters_.end(); i++) { for (auto j = i; ++j != clusters_.end();) { auto left = *i; auto right = *j; auto r_centroid = right->GetCentroid(); auto similarity = left->CosineSimilarity(r_centroid); if (similarity > threshold_) { auto templates = left->GetTemplates(); for (auto &fingerprint : templates) { right->AddTemplate(fingerprint); template_cluster_[fingerprint] = right; } right->UpdateCentroid(features_); to_delete.push_back(left); break; } } } // Delete the clusters that are empty for (auto cluster : to_delete) { clusters_.erase(cluster); delete cluster; } // Rebuild the KDTree to account for changed clusters kd_tree_.Build(clusters_); }
FollowTargetCollector( CBasePlayer *player ) { m_player = player; Vector playerVel = player->GetAbsVelocity(); m_forward.x = playerVel.x; m_forward.y = playerVel.y; float speed = m_forward.NormalizeInPlace(); Vector playerOrigin = GetCentroid( player ); const float walkSpeed = 100.0f; if (speed < walkSpeed) { m_cutoff.x = playerOrigin.x; m_cutoff.y = playerOrigin.y; m_forward.x = 0.0f; m_forward.y = 0.0f; } else { const float k = 1.5f; // 2.0f; float trimSpeed = min( speed, 200.0f ); m_cutoff.x = playerOrigin.x + k * trimSpeed * m_forward.x; m_cutoff.y = playerOrigin.y + k * trimSpeed * m_forward.y; } m_targetAreaCount = 0; }
void CHostageImprov::UpdateGrenadeReactions() { if (m_coughTimer.IsElapsed()) { if (TheBots->IsInsideSmokeCloud(&GetCentroid())) { m_coughTimer.Start(RANDOM_FLOAT(1, 3)); Chatter(HOSTAGE_CHATTER_COUGH); Frighten(SCARED); } } if (m_grenadeTimer.IsElapsed()) { CBaseEntity *entity = NULL; const float watchGrenadeRadius = 500.0f; m_grenadeTimer.Start(RANDOM_FLOAT(0.4f, 0.6f)); while ((entity = UTIL_FindEntityInSphere(entity, GetCentroid(), watchGrenadeRadius)) != NULL) { CGrenade *grenade = static_cast<CGrenade *>(entity); if (!FClassnameIs(grenade->pev, "grenade") || grenade->m_SGSmoke > 1) continue; if (IsVisible(grenade->Center())) { Chatter(HOSTAGE_CHATTER_SAW_HE_GRENADE); if (grenade->pev->dmg > 50.0f) { m_idleState.OnInjury(); Frighten(TERRIFIED); } else Frighten(SCARED); m_grenadeTimer.Start(10); break; } } } }
bool CHostageImprov::CanSeeRescueZone() const { if (TheCSBots() == NULL) return false; const CCSBotManager::Zone *zone = TheCSBots()->GetClosestZone(&GetCentroid()); if (zone != NULL) return IsVisible(zone->m_center); return false; }
/** * Return true if moving from "start" to "finish" will cross a player's line of fire. * The path from "start" to "finish" is assumed to be a straight line. * "start" and "finish" are assumed to be points on the ground. */ bool IsCrossingLineOfFire( const Vector &start, const Vector &finish, CBaseEntity *ignore, int ignoreTeam ) { for ( int p=1; p <= gpGlobals->maxClients; ++p ) { CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( p ) ); if (!IsEntityValid( player )) continue; if (player == ignore) continue; if (!player->IsAlive()) continue; if (ignoreTeam && player->GetTeamNumber() == ignoreTeam) continue; // compute player's unit aiming vector Vector viewForward; AngleVectors( player->EyeAngles() + player->GetPunchAngle(), &viewForward ); const float longRange = 5000.0f; Vector playerOrigin = GetCentroid( player ); Vector playerTarget = playerOrigin + longRange * viewForward; Vector result( 0, 0, 0 ); if (IsIntersecting2D( start, finish, playerOrigin, playerTarget, &result )) { // simple check to see if intersection lies in the Z range of the path float loZ, hiZ; if (start.z < finish.z) { loZ = start.z; hiZ = finish.z; } else { loZ = finish.z; hiZ = start.z; } if (result.z >= loZ && result.z <= hiZ + HumanHeight) return true; } } return false; }
/** * Plant the bomb. */ void PlantBombState::OnEnter( CCFBot *me ) { me->Crouch(); me->SetDisposition( CCFBot::SELF_DEFENSE ); // look at the floor // Vector down( myOrigin.x, myOrigin.y, -1000.0f ); float yaw = me->EyeAngles().y; Vector2D dir( BotCOS(yaw), BotSIN(yaw) ); Vector myOrigin = GetCentroid( me ); Vector down( myOrigin.x + 10.0f * dir.x, myOrigin.y + 10.0f * dir.y, me->GetFeetZ() ); me->SetLookAt( "Plant bomb on floor", down, PRIORITY_HIGH ); }
/* Find dimensionless coordinates by numerical methods input: pos is position in the element output: xipos is dimensionless position only used in MPM and only here if non-rectangular elements */ void ElementBase::GetXiPos(Vector *pos,Vector *xipos) const { double xt,yt,dxxi,dxeta,dyxi,dyeta; double deter,dxi,deta,dist; double gfn[MaxElNd],gdfnxi[MaxElNd],gdfnet[MaxElNd]; int numnds=NumberNodes(),i,j; // initial guess GetCentroid(xipos); // nodal coordinates Vector eNode[MaxElNd]; for(i=0;i<numnds;i++) { eNode[i].x=nd[nodes[i]]->x; eNode[i].y=nd[nodes[i]]->y; } /* solve for xipos using Newton-Rapheson (see FEA Notes) using shape functions and their derivatives */ for(j=1;j<=MAXITER;j++) { ShapeFunction(xipos,TRUE,gfn,gdfnxi,gdfnet,NULL,NULL,NULL,NULL); xt=-pos->x; yt=-pos->y; dxxi=0.; dxeta=0.; dyxi=0.; dyeta=0.; for(i=0;i<numnds;i++) { xt+=eNode[i].x*gfn[i]; yt+=eNode[i].y*gfn[i]; dxxi+=eNode[i].x*gdfnxi[i]; dxeta+=eNode[i].x*gdfnet[i]; dyxi+=eNode[i].y*gdfnxi[i]; dyeta+=eNode[i].y*gdfnet[i]; } deter=dxxi*dyeta-dxeta*dyxi; dxi=(-xt*dyeta+yt*dxeta)/deter; deta=(xt*dyxi-yt*dxxi)/deter; xipos->x+=dxi; xipos->y+=deta; dist=sqrt(dxi*dxi+deta*deta); if(dist<.001) break; } }
bool CHostageImprov::__MAKE_VHOOK(IsPlayerLookingAtMe)(CBasePlayer *other, float cosTolerance) const { Vector2D toOther = (other->pev->origin - GetCentroid()).Make2D(); toOther.NormalizeInPlace(); UTIL_MakeVectors(other->pev->punchangle + other->pev->v_angle); Vector2D otherDir = gpGlobals->v_forward.Make2D(); otherDir.NormalizeInPlace(); if (-cosTolerance > DotProduct(toOther, otherDir)) { if (IsVisible(other->EyePosition())) { return true; } } return false; }
CBasePlayer *CHostageImprov::GetClosestVisiblePlayer(int team) { CBasePlayer *close = NULL; float closeRangeSq = 1e8f; for (int i = 0; i < m_visiblePlayerCount; ++i) { CBasePlayer *player = (CBasePlayer *)m_visiblePlayer[i]; if (player == NULL || (team > 0 && player->m_iTeam != team)) continue; float_precision rangeSq = (GetCentroid() - player->pev->origin).LengthSquared(); if (rangeSq < closeRangeSq) { closeRangeSq = rangeSq; close = player; } } return close; }
/** * Reset internal data to initial state */ void CCFBot::ResetValues( void ) { m_chatter.Reset(); m_gameState.Reset(); m_avoid = NULL; m_avoidTimestamp = 0.0f; m_hurryTimer.Invalidate(); m_alertTimer.Invalidate(); m_sneakTimer.Invalidate(); m_noiseBendTimer.Invalidate(); m_bendNoisePositionValid = false; m_isStuck = false; m_stuckTimestamp = 0.0f; m_wiggleTimer.Invalidate(); m_stuckJumpTimer.Invalidate(); m_pathLength = 0; m_pathIndex = 0; m_areaEnteredTimestamp = 0.0f; m_currentArea = NULL; m_lastKnownArea = NULL; m_isStopping = false; m_avoidFriendTimer.Invalidate(); m_isFriendInTheWay = false; m_isWaitingBehindFriend = false; m_isAvoidingGrenade.Invalidate(); StopPanicking(); m_disposition = ENGAGE_AND_INVESTIGATE; m_enemy = NULL; m_grenadeTossState = NOT_THROWING; m_initialEncounterArea = NULL; m_wasSafe = true; m_nearbyEnemyCount = 0; m_enemyPlace = 0; m_nearbyFriendCount = 0; m_closestVisibleFriend = NULL; m_closestVisibleHumanFriend = NULL; m_closestVisibleKO = NULL; for( int w=0; w<MAX_PLAYERS; ++w ) { m_watchInfo[w].timestamp = 0.0f; m_watchInfo[w].isEnemy = false; m_playerTravelDistance[ w ] = -1.0f; } // randomly offset each bot's timer to spread computation out m_updateTravelDistanceTimer.Start( RandomFloat( 0.0f, 0.9f ) ); m_travelDistancePhase = 0; m_isEnemyVisible = false; m_visibleEnemyParts = VIS_NONE; m_lastSawEnemyTimestamp = -999.9f; m_firstSawEnemyTimestamp = 0.0f; m_currentEnemyAcquireTimestamp = 0.0f; m_isLastEnemyDead = true; m_attacker = NULL; m_attackedTimestamp = 0.0f; m_enemyDeathTimestamp = 0.0f; m_friendDeathTimestamp = 0.0f; m_lastVictimID = 0; m_isAimingAtEnemy = false; m_fireWeaponTimestamp = 0.0f; m_equipTimer.Invalidate(); m_zoomTimer.Invalidate(); m_isFollowing = false; m_leader = NULL; m_followTimestamp = 0.0f; m_allowAutoFollowTime = 0.0f; m_enemyQueueIndex = 0; m_enemyQueueCount = 0; m_enemyQueueAttendIndex = 0; m_bomber = NULL; m_isEnemySniperVisible = false; m_sawEnemySniperTimer.Invalidate(); m_lookAroundStateTimestamp = 0.0f; m_inhibitLookAroundTimestamp = 0.0f; m_lookPitch = 0.0f; m_lookPitchVel = 0.0f; m_lookYaw = 0.0f; m_lookYawVel = 0.0f; m_aimOffsetTimestamp = 0.0f; m_aimSpreadTimestamp = 0.0f; m_lookAtSpotState = NOT_LOOKING_AT_SPOT; for( int p=0; p<MAX_PLAYERS; ++p ) { m_partInfo[p].m_validFrame = 0; } m_spotEncounter = NULL; m_spotCheckTimestamp = 0.0f; m_peripheralTimestamp = 0.0f; m_avgVelIndex = 0; m_avgVelCount = 0; m_lastOrigin = GetCentroid(); m_voiceEndTimestamp = 0.0f; m_noisePosition = Vector( 0, 0, 0 ); m_noiseTimestamp = 0.0f; m_stateTimestamp = 0.0f; m_task = SEEK_AND_DESTROY; m_taskEntity = NULL; m_approachPointCount = 0; m_approachPointViewPosition.x = 99999999999.9f; m_approachPointViewPosition.y = 0.0f; m_approachPointViewPosition.z = 0.0f; m_checkedHidingSpotCount = 0; StandUp(); Run(); m_mustRunTimer.Invalidate(); m_waitTimer.Invalidate(); m_pathLadder = NULL; m_repathTimer.Invalidate(); m_huntState.ClearHuntArea(); m_hasVisitedEnemySpawn = false; m_stillTimer.Invalidate(); // adjust morale - if we died, our morale decreased, // but if we live, no adjustement (round win/loss also adjusts morale) if (m_diedLastRound) DecreaseMorale(); m_diedLastRound = false; // IsRogue() randomly changes this m_isRogue = false; m_surpriseTimer.Invalidate(); // even though these are EHANDLEs, they need to be NULL-ed m_goalEntity = NULL; m_avoid = NULL; m_enemy = NULL; for ( int i=0; i<MAX_ENEMY_QUEUE; ++i ) { m_enemyQueue[i].player = NULL; m_enemyQueue[i].isReloading = false; m_enemyQueue[i].isProtectedByShield = false; } // start in idle state m_isOpeningDoor = false; StopAttacking(); Idle(); }
void DataManager::Initialize(itk::SmartPointer<LabelMapType> labelMap, std::shared_ptr<Coordinates> coordinates, std::shared_ptr<Metadata> metadata) { m_orientationData = coordinates; auto spacing = m_orientationData->GetImageSpacing(); auto imageorigin = m_orientationData->GetImageOrigin(); auto imagesize = m_orientationData->GetImageSize(); // insert background label info, initially all voxels are background, we'll subtract later auto object = std::make_shared<ObjectInformation>(); object->scalar = 0; object->centroid = Vector3d((imagesize[0] / 2.0) * spacing[0], (imagesize[1] / 2.0) * spacing[1], (imagesize[2] / 2.0) / spacing[2]); object->size = imagesize[0] * imagesize[1] * imagesize[2]; object->min = Vector3ui(0, 0, 0); object->max = Vector3ui(imagesize[0], imagesize[1], imagesize[2]); ObjectVector.insert(std::pair<unsigned short, std::shared_ptr<ObjectInformation>>(0, object)); // evaluate shapelabelobjects to get the centroid of the object auto evaluator = itk::ShapeLabelMapFilter<LabelMapType>::New(); evaluator->SetInput(labelMap); evaluator->ComputePerimeterOff(); evaluator->ComputeFeretDiameterOff(); evaluator->SetInPlace(true); evaluator->Update(); // get voxel count for each label for statistics and "flatten" the labelmap (make all labels consecutive starting from 1) auto labelChanger = ChangeType::New(); labelChanger->SetInput(evaluator->GetOutput()); labelChanger->SetInPlace(true); ImageRegionType region; unsigned short i = 1; itk::Point<double, 3> centroid; for (int i = 0; i < evaluator->GetOutput()->GetNumberOfLabelObjects(); ++i) { auto labelObject = evaluator->GetOutput()->GetNthLabelObject(i); auto scalar = labelObject->GetLabel(); centroid = labelObject->GetCentroid(); region = labelObject->GetBoundingBox(); auto regionOrigin = region.GetIndex(); auto regionSize = region.GetSize(); object = std::make_shared<ObjectInformation>(); object->scalar = scalar; object->centroid = Vector3d(centroid[0] / spacing[0], centroid[1] / spacing[1], centroid[2] / spacing[2]); object->size = labelObject->Size(); object->min = Vector3ui(regionOrigin[0], regionOrigin[1], regionOrigin[2]); object->max = Vector3ui(regionSize[0] + regionOrigin[0], regionSize[1] + regionOrigin[1], regionSize[2] + regionOrigin[2]) - Vector3ui(1, 1, 1); ObjectVector.insert(std::pair<unsigned short, std::shared_ptr<ObjectInformation>>(i, object)); // substract the voxels of this object from the background label ObjectVector[0]->size -= labelObject->Size(); // need to mark object label as used to correct errors in the segmha metadata (defined labels but empty objects) metadata->markAsUsed(scalar); // flatten label labelChanger->SetChange(scalar, i); } // start entering new labels at the end of the scalar range m_firstFreeValue = GetScalarForLabel(GetNumberOfLabels() - 1) + 1; // apply all the changes made to labels labelChanger->Update(); m_labelMap = LabelMapType::New(); m_labelMap = labelChanger->GetOutput(); m_labelMap->Optimize(); m_labelMap->Update(); // generate the initial vtkLookupTable m_lookupTable = vtkSmartPointer<vtkLookupTable>::New(); GenerateLookupTable(); m_lookupTable->Modified(); }
/**--------------------------------------------------------------------------<BR> C2DPolyArc::RotateToRight <BR> \brief Rotates the polygon to the right around the centroid. <P>---------------------------------------------------------------------------*/ void C2DPolyArc::RotateToRight(double dAng) { C2DPolyBase::RotateToRight( dAng, GetCentroid()); }
int C_CFPlayer::DrawModel( int flags ) { // if local player is spectating this player in first person mode, don't draw it C_CFPlayer * pPlayer = GetLocalCFPlayer(); if (m_bIsDecapitated) SetBodygroup(1, 1); else if ((!input->CAM_IsThirdPerson() && pPlayer == this) || pPlayer->IsFirstPersonSpectating(this)) SetBodygroup(1, 1); else SetBodygroup(1, 0); if (IsFuse()) { if ((!input->CAM_IsThirdPerson() && pPlayer == this) || pPlayer->IsFirstPersonSpectating(this)) SetBodygroup(2, 0); else SetBodygroup(2, 1); } // Skip C_BasePlayer::DrawModel() because it has a bunch of logic we don't care for. int iResult = C_BaseCombatCharacter::DrawModel( flags ); if (C_CFPlayer::GetLocalCFPlayer() == this || pPlayer->IsObserver() && pPlayer->GetObserverTarget() && ToCFPlayer(pPlayer->GetObserverTarget()) == this) DrawTargets(); // Put submodels back where they are supposed to be so that shadows and such render them properly. SetBodygroup(1, m_bIsDecapitated); if (IsFuse()) SetBodygroup(2, 1); if (gpGlobals->curtime - m_flShieldTime < 0.5f) { Vector vecDmgDirection = m_vecShieldDmgOrigin - GetCentroid(); QAngle angShield; VectorAngles(vecDmgDirection, angShield); m_pBarrier->SetAbsAngles(angShield); m_pBarrier->SetAbsOrigin(GetAbsOrigin()); float flAlpha = 0; if ((gpGlobals->curtime - m_flShieldTime) < 0.2f) flAlpha = RemapVal(gpGlobals->curtime - m_flShieldTime, 0.0f, 0.2f, 0, 255); else flAlpha = RemapVal(gpGlobals->curtime - m_flShieldTime, 0.2f, 0.5f, 255, 0); flAlpha *= m_flShieldStrength; if (C_CFPlayer::GetLocalCFPlayer() == this) flAlpha /= 2; if (flAlpha) { m_pBarrier->SetBodygroup(0, m_bShieldPhysical); m_pBarrier->SetRenderColorA(flAlpha); m_pBarrier->DrawModel(flags); } } return iResult; }
void CHostageImprov::__MAKE_VHOOK(OnGameEvent)(GameEventType event, CBaseEntity *entity, CBaseEntity *other) { switch (event) { case EVENT_BULLET_IMPACT: { Vector *impactPos = (Vector *)other; const float nearRange = 100.0f; if ((GetCentroid() - *impactPos).IsLengthLessThan(nearRange)) { Frighten(TERRIFIED); } break; } case EVENT_PLAYER_DIED: case EVENT_HOSTAGE_KILLED: if (IsVisible(entity->pev->origin, true)) { Frighten(TERRIFIED); if (!entity->IsPlayer() || entity->IsPlayer() && ((CBasePlayer *)entity)->m_iTeam != TERRORIST) { DelayedChatter(RANDOM_FLOAT(0.5f, 0.7f), HOSTAGE_CHATTER_SCARED_OF_MURDER, true); } if (!entity->IsPlayer()) { m_idleState.OnInjury(); } } break; case EVENT_HOSTAGE_RESCUED: if (m_hostage == other) { if (!entity) return; Chatter(HOSTAGE_CHATTER_RESCUED, false); } break; case EVENT_TERRORISTS_WIN: Frighten(SCARED); m_isDelayedChatterPending = false; DelayedChatter(RANDOM_FLOAT(1.0f, 4.0f), HOSTAGE_CHATTER_TERRORISTS_WIN); return; case EVENT_CTS_WIN: m_scaredTimer.Invalidate(); m_isDelayedChatterPending = false; DelayedChatter(RANDOM_FLOAT(1.0f, 4.0f), HOSTAGE_CHATTER_CTS_WIN); return; } float range; PriorityType priority; bool isHostile; if (entity != NULL && IsGameEventAudible(event, entity, other, &range, &priority, &isHostile)) { const float fudge = 0.4f; if ((m_hostage->pev->origin - entity->pev->origin).IsLengthLessThan(range * fudge)) { m_lastNoiseTimer.Start(); if (isHostile) { Frighten(SCARED); switch (event) { case EVENT_WEAPON_FIRED: { DelayedChatter(RANDOM_FLOAT(0.3f, 1.0f), HOSTAGE_CHATTER_SCARED_OF_GUNFIRE); break; } case EVENT_HE_GRENADE_EXPLODED: case EVENT_SMOKE_GRENADE_EXPLODED: case EVENT_BREAK_GLASS: case EVENT_BREAK_WOOD: case EVENT_BREAK_METAL: case EVENT_BREAK_FLESH: case EVENT_BREAK_CONCRETE: DelayedChatter(RANDOM_FLOAT(0.3f, 1.0f), HOSTAGE_CHATTER_LOOK_OUT); break; default: break; } } } } if (event == EVENT_FLASHBANG_GRENADE_EXPLODED) { Vector *impactPos = (Vector *)other; const float flashRange = 1000.0f; if ((GetEyes() - *impactPos).IsLengthLessThan(flashRange) && IsVisible(*impactPos)) { DelayedChatter(RANDOM_FLOAT(0.0f, 1.0f), HOSTAGE_CHATTER_BLINDED, true); Frighten(TERRIFIED); } } }
/** * 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(); } } }