// --------------------------------------------------------------------------- // // ROUTINE: CAINodeMgr::FindNearestNodeInFrontWithFromThreat // // PURPOSE: Finds the nearest node that has an OK status from the hThreat, // and which is between the checker and the threat // // --------------------------------------------------------------------------- AINode* CAINodeMgr::FindNearestNodeInSameDirectionAsThreat(CAI* pAI, EnumAINodeType eNodeType, const LTVector& vPos, HOBJECT hThreat) { LTFLOAT fMinDistance = (float)INT_MAX; AINode* pClosestNode = LTNULL; // Get AIs Path Knowledge. CAIPathKnowledgeMgr* pPathKnowledgeMgr = LTNULL; if( pAI && pAI->GetPathKnowledgeMgr() ) { pPathKnowledgeMgr = pAI->GetPathKnowledgeMgr(); } AINode* pNode; AINODE_MAP::iterator it; for(it = m_mapAINodes.lower_bound(eNodeType); it != m_mapAINodes.upper_bound(eNodeType); ++it) { pNode = it->second; // Skip nodes in unreachable volumes. if( pPathKnowledgeMgr && ( pPathKnowledgeMgr->GetPathKnowledge( pNode->GetNodeContainingVolume() ) == CAIPathMgr::kPath_NoPathFound ) ) { continue; } // Skip nodes that are not in volumes. if( !pNode->GetNodeContainingVolume() ) { continue; } // Skip node if required alignment does not match. if( ( pNode->GetRequiredRelationTemplateID() != -1 ) && ( pNode->GetRequiredRelationTemplateID() != pAI->GetRelationMgr()->GetTemplateID() ) ) { continue; } if ( pNode->IsLockedDisabledOrTimedOut() ) continue; if ( AreNodeAndObjectInSameDirection(hThreat, pNode, vPos) ) continue; LTFLOAT fDistanceSqr = VEC_DISTSQR(vPos, pNode->GetPos()); if ( (fDistanceSqr > fMinDistance) || (fDistanceSqr > pNode->GetRadiusSqr()) ) continue; if ( kStatus_Ok == pNode->GetStatus(vPos, hThreat) ) { fMinDistance = fDistanceSqr; pClosestNode = pNode; } } // Ensure that AI can pathfind to the destination node. // Ideally, we would like to do this check for each node as we iterate, // but that could result in multiple runs of BuildVolumePath() which // is expensive. So instead we just check the final returned node. // The calling code can call this function again later, and will not get // this node again. if( pAI && pClosestNode ) { AIVolume* pVolumeDest = pClosestNode->GetNodeContainingVolume(); if( !g_pAIPathMgr->HasPath( pAI, pVolumeDest ) ) { return LTNULL; } } return pClosestNode; }
AINode* CAINodeMgr::FindRandomNodeFromThreat(CAI* pAI, EnumAINodeType eNodeType, const LTVector& vPos, HOBJECT hThreat) { s_lstTempNodes.clear(); // Get AIs Path Knowledge. CAIPathKnowledgeMgr* pPathKnowledgeMgr = LTNULL; if( pAI && pAI->GetPathKnowledgeMgr() ) { pPathKnowledgeMgr = pAI->GetPathKnowledgeMgr(); } // Generate list of valid nodes. AINode* pNode; AINODE_MAP::iterator it; for(it = m_mapAINodes.lower_bound(eNodeType); it != m_mapAINodes.upper_bound(eNodeType); ++it) { pNode = it->second; // Skip nodes in unreachable volumes. if( pPathKnowledgeMgr && ( pPathKnowledgeMgr->GetPathKnowledge( pNode->GetNodeContainingVolume() ) == CAIPathMgr::kPath_NoPathFound ) ) { continue; } // Skip nodes that are not in volumes. if( !pNode->GetNodeContainingVolume() ) { continue; } // Skip node if required alignment does not match. if( ( pNode->GetRequiredRelationTemplateID() != -1 ) && ( pNode->GetRequiredRelationTemplateID() != pAI->GetRelationMgr()->GetTemplateID() ) ) { continue; } if( !pNode->NodeTypeIsActive( eNodeType ) ) { continue; } if ( !pNode->IsLockedDisabledOrTimedOut() ) { if ( kStatus_Ok == pNode->GetStatus(vPos, hThreat) ) { s_lstTempNodes.push_back( pNode ); } } } // Randomly select one of the valid nodes. if( !s_lstTempNodes.empty() ) { pNode = s_lstTempNodes[ GetRandom( 0, s_lstTempNodes.size() - 1 ) ]; s_lstTempNodes.clear(); } else { pNode = LTNULL; } // Ensure that AI can pathfind to the destination node. // Ideally, we would like to do this check for each node as we iterate, // but that could result in multiple runs of BuildVolumePath() which // is expensive. So instead we just check the final returned node. // The calling code can call this function again later, and will not get // this node again. if( pAI && pNode ) { AIVolume* pVolumeDest = pNode->GetNodeContainingVolume(); if( !g_pAIPathMgr->HasPath( pAI, pVolumeDest ) ) { return LTNULL; } } return pNode; }