void CAI_PlaneSolver::GenerateObstacleNpcs( const AILocalMoveGoal_t &goal, float probeDist ) { if ( !ProbeForNpcs() ) { CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); Vector minsSelf, maxsSelf; m_pNpc->CollisionProp()->WorldSpaceSurroundingBounds( &minsSelf, &maxsSelf ); float radiusSelf = (minsSelf.AsVector2D() - maxsSelf.AsVector2D()).Length() * 0.5; for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ ) { CAI_BaseNPC *pAI = ppAIs[i]; if ( pAI != m_pNpc && pAI->IsAlive() && ( !goal.pPath || pAI != goal.pPath->GetTarget() ) ) { Vector mins, maxs; pAI->CollisionProp()->WorldSpaceSurroundingBounds( &mins, &maxs ); if ( mins.z < maxsSelf.z + 12.0 && maxs.z > minsSelf.z - 12.0 ) { float radius = (mins.AsVector2D() - maxs.AsVector2D()).Length() * 0.5; float distance = ( pAI->GetAbsOrigin().AsVector2D() - m_pNpc->GetAbsOrigin().AsVector2D() ).Length(); if ( distance - radius < radiusSelf + probeDist ) { AddObstacle( pAI->WorldSpaceCenter(), radius, pAI, AIMST_AVOID_NPC ); } } } } #ifdef SecobMod__Enable_Fixed_Multiplayer_AI CBaseEntity *pPlayer = UTIL_GetNearestPlayer(m_pNpc->GetAbsOrigin()); #else CBaseEntity *pPlayer = UTIL_PlayerByIndex( 1 ); #endif //SecobMod__Enable_Fixed_Multiplayer_AI if ( pPlayer ) { Vector mins, maxs; pPlayer->CollisionProp()->WorldSpaceSurroundingBounds( &mins, &maxs ); if ( mins.z < maxsSelf.z + 12.0 && maxs.z > minsSelf.z - 12.0 ) { float radius = (mins.AsVector2D() - maxs.AsVector2D()).Length(); float distance = ( pPlayer->GetAbsOrigin().AsVector2D() - m_pNpc->GetAbsOrigin().AsVector2D() ).Length(); if ( distance - radius < radiusSelf + probeDist ) { AddObstacle( pPlayer->WorldSpaceCenter(), radius, pPlayer, AIMST_AVOID_NPC ); } } } } }
AI_SuggestorResult_t CAI_PlaneSolver::GenerateObstacleSuggestion( const AILocalMoveGoal_t &goal, float yawScanCenter, float probeDist, float spanPerProbe, int probeOffset) { AIMoveTrace_t moveTrace; float yawTest; float arcCenter; CalcYawsFromOffset( yawScanCenter, spanPerProbe, probeOffset, &yawTest, &arcCenter ); Vector probeDir = UTIL_YawToVector( yawTest ); float requiredMovement = goal.speed * GetMotor()->GetMoveInterval(); // Probe immediate move with footing, then look further out ignoring footing bool fTraceClear = true; if ( probeDist > requiredMovement ) { if ( !MoveLimit( goal.navType, GetLocalOrigin() + probeDir * requiredMovement, !ProbeForNpcs(), true, &moveTrace ) ) { fTraceClear = false; moveTrace.flDistObstructed = (probeDist - requiredMovement) + moveTrace.flDistObstructed; } } if ( fTraceClear ) { fTraceClear = MoveLimit( goal.navType, GetLocalOrigin() + probeDir * probeDist, !ProbeForNpcs(), false, &moveTrace ); } if ( !fTraceClear ) { GenerateSuggestionFromTrace( goal, moveTrace, probeDist, arcCenter, spanPerProbe, probeOffset ); return SR_OK; } return SR_NONE; }
bool CAI_PlaneSolver::MoveLimit( Navigation_t navType, const Vector &target, bool ignoreTransients, bool fCheckStep, int contents, AIMoveTrace_t *pMoveTrace ) { AI_PROFILE_SCOPE( CAI_PlaneSolver_MoveLimit ); int flags = ( navType == NAV_GROUND ) ? AIMLF_2D : AIMLF_DEFAULT; if ( ignoreTransients ) { Assert( !ProbeForNpcs() ); flags |= AIMLF_IGNORE_TRANSIENTS; } CAI_MoveProbe *pProbe = m_pNpc->GetMoveProbe(); return pProbe->MoveLimit( navType, GetLocalOrigin(), target, contents, m_pNpc->GetNavTargetEntity(), (fCheckStep) ? 100 : 0, flags, pMoveTrace ); }
AI_SuggestorResult_t CAI_PlaneSolver::GenerateObstacleSuggestions( const AILocalMoveGoal_t &goal, const AIMoveTrace_t &directTrace, float distClear, float probeDist, float degreesToProbe, int nProbes ) { Assert( nProbes % 2 == 1 ); PLANESOLVER_PROFILE_SCOPE( CAI_PlaneSolver_GenerateObstacleSuggestions ); AI_SuggestorResult_t seekResult = SR_NONE; bool fNewTarget = ( !m_fSolvedPrev || m_PrevTarget != goal.target ); if ( fNewTarget ) m_RefreshSamplesTimer.Force(); if ( PLANE_SOLVER_THINK_FREQUENCY[AIStrongOpt()] == 0.0 || m_RefreshSamplesTimer.Expired() ) { m_Solver.ClearRegulations(); if ( !ProbeForNpcs() ) GenerateObstacleNpcs( goal, probeDist ); if ( GenerateCircleObstacleSuggestions( goal, probeDist ) ) seekResult = SR_OK; float spanPerProbe = degreesToProbe / nProbes; int nSideProbes = (nProbes - 1) / 2; float yawGoalDir = UTIL_VecToYaw( goal.dir ); Vector probeTarget; AIMoveTrace_t moveTrace; int i; // Generate suggestion from direct trace, or probe if direct trace doesn't match if ( fabs( probeDist - ( distClear + directTrace.flDistObstructed ) ) < 0.1 && ( ProbeForNpcs() || directTrace.fStatus != AIMR_BLOCKED_NPC ) ) { if ( directTrace.fStatus != AIMR_OK ) { seekResult = SR_OK; GenerateSuggestionFromTrace( goal, directTrace, probeDist, yawGoalDir, spanPerProbe, 0 ); } } else if ( GenerateObstacleSuggestion( goal, yawGoalDir, probeDist, spanPerProbe, 0 ) == SR_OK ) { seekResult = SR_OK; } // Scan left. Note that in the left and right scan, the algorithm stops as soon // as there is a clear path. This is an optimization in anticipation of the // behavior of the underlying solver. This will break more often the higher // PLANE_SOLVER_THINK_FREQUENCY becomes bool foundClear = false; for ( i = 1; i <= nSideProbes; i++ ) { if ( !foundClear ) { AI_SuggestorResult_t curSeekResult = GenerateObstacleSuggestion( goal, yawGoalDir, probeDist, spanPerProbe, i ); if ( curSeekResult == SR_OK ) { seekResult = SR_OK; } else foundClear = true; } else { float ignored; float arcCenter; CalcYawsFromOffset( yawGoalDir, spanPerProbe, i, &ignored, &arcCenter ); m_Solver.AddRegulation( AI_MoveSuggestion_t( AIMST_NO_KNOWLEDGE, 1, arcCenter, spanPerProbe ) ); } } // Scan right foundClear = false; for ( i = -1; i >= -nSideProbes; i-- ) { if ( !foundClear ) { AI_SuggestorResult_t curSeekResult = GenerateObstacleSuggestion( goal, yawGoalDir, probeDist, spanPerProbe, i ); if ( curSeekResult == SR_OK ) { seekResult = SR_OK; } else foundClear = true; } else { float ignored; float arcCenter; CalcYawsFromOffset( yawGoalDir, spanPerProbe, i, &ignored, &arcCenter ); m_Solver.AddRegulation( AI_MoveSuggestion_t( AIMST_NO_KNOWLEDGE, 1, arcCenter, spanPerProbe ) ); } } if ( seekResult == SR_OK ) { float arcCenter = yawGoalDir - 180; if ( arcCenter < 0 ) arcCenter += 360; // Since these are not sampled every think, place a negative arc in all directions not sampled m_Solver.AddRegulation( AI_MoveSuggestion_t( AIMST_NO_KNOWLEDGE, 1, arcCenter, 360 - degreesToProbe ) ); } m_RefreshSamplesTimer.Reset( PLANE_SOLVER_THINK_FREQUENCY[AIStrongOpt()] ); } else if ( m_Solver.HaveRegulations() ) seekResult = SR_OK; return seekResult; }