void CAISensorNode::AssignNodeConfidenceValues( AIVALID_NODE_LIST& lstValidNodes, float fMaxDistSqr ) { // Create memories for each node. // The confidence value is the relative to the distance to the node. AINode* pNode; CAIWMFact* pFact; float fConfidence; SAIVALID_NODE* pValidNode; AIVALID_NODE_LIST::iterator itNode; for( itNode = lstValidNodes.begin(); itNode != lstValidNodes.end(); ++itNode ) { pValidNode = &*itNode; pFact = m_pAI->GetAIWorkingMemory()->CreateWMFact( kFact_Node ); pFact->SetNodeType( m_pSensorRecord->eNodeType, 1.f ); pFact->SetTargetObject( pValidNode->hNode, 1.f ); pNode = (AINode*)g_pLTServer->HandleToObject( pValidNode->hNode ); if( pNode ) { fConfidence = ( fMaxDistSqr - pValidNode->fDistSqr ) / fMaxDistSqr; pFact->SetPos( pNode->GetPos(), fConfidence ); } } }
void CAINodeMgr::EnumerateNodesInVolume(EnumAINodeType eNodeType, AIVolume* pVolume, LTFLOAT fVertThreshold, AINode** apNodes, uint32* pcNodes, const uint32 nMaxSearchNodes) { if(nMaxSearchNodes == (*pcNodes)) { return; } AINode* pNode; AINODE_MAP::const_iterator it; for(it = m_mapAINodes.lower_bound(eNodeType); it != m_mapAINodes.upper_bound(eNodeType); ++it) { pNode = it->second; if( pVolume->InsideMasked(pNode->GetPos(), eAxisAll, 53.0f) ) { apNodes[(*pcNodes)++] = pNode; if(nMaxSearchNodes == *pcNodes) { return; } } } }
void CAIActionReactToDanger::SearchForDangerOrigin( CAI* pAI, const LTVector& vDangerPos ) { // Sanity check. if( !( pAI && pAI->CanSearch() ) ) { return; } // Find an existing memory for the desire to search, or create one. CAIWMFact factQuery; factQuery.SetFactType(kFact_Desire); factQuery.SetDesireType(kDesire_Search); CAIWMFact* pFactSearch = pAI->GetAIWorkingMemory()->FindWMFact( factQuery ); if( !pFactSearch ) { pFactSearch = pAI->GetAIWorkingMemory()->CreateWMFact( kFact_Desire ); } // Search from the nearest search node to the danger position. LTVector vSearchOrigin = vDangerPos; AINode* pNode = g_pAINodeMgr->FindNearestNodeInRadius( pAI, kNode_Search, vDangerPos, 1000.f, true ); if( pNode ) { vSearchOrigin = pNode->GetPos(); } // Setup the current desire. if( pFactSearch ) { pFactSearch->SetDesireType( kDesire_Search, 1.f ); pFactSearch->SetPos( vSearchOrigin, 1.f ); } }
AINode* CAINodeMgr::FindNearestObjectNode(CAI* pAI, EnumAINodeType eNodeType, const LTVector& vPos, const char* szClass) { LTFLOAT fMinDistanceSqr = (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->NodeTypeIsActive( eNodeType ) ) { continue; } if ( !pNode->IsLockedDisabledOrTimedOut() && pNode->HasObject() ) { LTFLOAT fDistanceSqr = VEC_DISTSQR(vPos, pNode->GetPos()); if ( (fDistanceSqr < fMinDistanceSqr) && (fDistanceSqr < pNode->GetRadiusSqr()) ) { HOBJECT hObject; if ( LT_OK == FindNamedObject(pNode->GetObject(), hObject) ) { HCLASS hClass = g_pLTServer->GetClass((char*)szClass); if ( g_pLTServer->IsKindOf(g_pLTServer->GetObjectClass(hObject), hClass) ) { fMinDistanceSqr = 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::FindNearestNodeFromThreat(CAI* pAI, EnumAINodeType eNodeType, const LTVector& vPos, HOBJECT hThreat, LTFLOAT fSearchFactor) { 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->NodeTypeIsActive( eNodeType ) ) { continue; } if ( !pNode->IsLockedDisabledOrTimedOut() ) { // Check of there is a SearchFactor, scaling the radius of the node. LTFLOAT fNodeRadiusSqr; if( fSearchFactor != 1.f ) { fNodeRadiusSqr = pNode->GetRadius() * fSearchFactor; fNodeRadiusSqr *= fNodeRadiusSqr; } else { fNodeRadiusSqr = pNode->GetRadiusSqr(); } LTFLOAT fDistanceSqr = VEC_DISTSQR(vPos, pNode->GetPos()); if ( ( fDistanceSqr < fMinDistance ) && ( fDistanceSqr < fNodeRadiusSqr ) ) { 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; }
AINodeTail* CAINodeMgr::FindTailNode(CAI* pAI, const LTVector& vTargetPos, const LTVector& vPos) { LTFLOAT fTailedDistance; LTFLOAT fTailerDistance; LTFLOAT fMinTailedDistance = (float)INT_MAX; LTFLOAT fMinTailerDistance = (float)INT_MAX; AINode* pNode; AINode* pTailedNode = LTNULL; AINode* pTailerNode = LTNULL; AINODE_MAP::iterator it; // Get AIs Path Knowledge. CAIPathKnowledgeMgr* pPathKnowledgeMgr = LTNULL; if( pAI && pAI->GetPathKnowledgeMgr() ) { pPathKnowledgeMgr = pAI->GetPathKnowledgeMgr(); } // Find the node closest to the tailed object and to the tailer. for(it = m_mapAINodes.lower_bound(kNode_Tail); it != m_mapAINodes.upper_bound(kNode_Tail); ++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; } fTailedDistance = VEC_DISTSQR(vTargetPos, pNode->GetPos()); fTailerDistance = VEC_DISTSQR(vPos, pNode->GetPos()); if ( fTailedDistance < fMinTailedDistance ) { pTailedNode = pNode; fMinTailedDistance = fTailedDistance; } if ( fTailerDistance < fMinTailerDistance ) { pTailerNode = pNode; fMinTailerDistance = fTailerDistance; } } // Figure out what the tail node is based on these two nodes uint32 iTailedNode = GetNodeIndexFromName( pTailedNode ); uint32 iTailerNode = GetNodeIndexFromName( pTailerNode ); uint32 iTailNode = -1; // If the tailer is less than the tailed node, the tail is the tailed node minus 1 if ( iTailerNode < iTailedNode ) { iTailNode = Max<uint32>(0, iTailedNode-1); } // If the tailer is greater than the tailed node, the tail is the tailed node plus 1 if ( iTailerNode > iTailedNode ) { iTailNode = Min<uint32>( m_mapAINodes.count(kNode_Tail)-1, iTailedNode+1); } // If the tail node is equal to the tailednode, then there is no good node to go to. if ( iTailerNode == iTailedNode ) { return LTNULL; } else { AINodeTail* pNodeTail = (AINodeTail*)FindNodeByIndex(kNode_Tail, iTailNode); // 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 && pNodeTail ) { AIVolume* pVolumeDest = pNodeTail->GetNodeContainingVolume(); if( !g_pAIPathMgr->HasPath( pAI, pVolumeDest ) ) { return LTNULL; } } return pNodeTail; } }
AINode* CAINodeMgr::FindNearestOwnedNode(CAI* pAI, EnumAINodeType eNodeType, const LTVector& vPos, HOBJECT hOwner) { // It is NOT OK for hOwner to be NULL. Only return nodes that are owned by someone. if( !hOwner ) { return LTNULL; } // Get AIs Path Knowledge. CAIPathKnowledgeMgr* pPathKnowledgeMgr = LTNULL; if( pAI && pAI->GetPathKnowledgeMgr() ) { pPathKnowledgeMgr = pAI->GetPathKnowledgeMgr(); } LTFLOAT fMinDistanceSqr = (float)INT_MAX; AINode* pClosestNode = LTNULL; 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->GetNodeOwner() != hOwner ) { continue; } // Owned nodes are locked by the owner, so just check for // disabled and timed out. if ( !( pNode->IsDisabled() || pNode->IsTimedOut() ) ) { LTFLOAT fDistanceSqr = VEC_DISTSQR(vPos, pNode->GetPos()); if ( fDistanceSqr < fMinDistanceSqr ) { fMinDistanceSqr = 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; }