//--------------------------------------------------------- //--------------------------------------------------------- void CAI_Relationship::ChangeRelationships( int disposition, int iReverting, CBaseEntity *pActivator, CBaseEntity *pCaller ) { if( iReverting != NOT_REVERTING && m_iPreviousDisposition == -1 ) { // Trying to revert without having ever set the relationships! DevMsg( 2, "ai_relationship cannot revert changes before they are applied!\n"); return; } const int MAX_HANDLED = 512; CUtlVectorFixed<CBaseCombatCharacter *, MAX_HANDLED> subjectList; CUtlVectorFixed<CBaseCombatCharacter *, MAX_HANDLED> targetList; // Add any special subjects we found CBaseEntity *pSpecialSubject = FindEntityForProceduralName( m_iszSubject, pActivator, pCaller ); if ( pSpecialSubject && pSpecialSubject->MyCombatCharacterPointer() ) { subjectList.AddToTail( pSpecialSubject->MyCombatCharacterPointer() ); } // Add any special targets we found CBaseEntity *pSpecialTarget = FindEntityForProceduralName( m_target, pActivator, pCaller ); if ( pSpecialTarget && pSpecialTarget->MyCombatCharacterPointer() ) { targetList.AddToTail( pSpecialTarget->MyCombatCharacterPointer() ); } // ------------------------------- // Search for targets and subjects // ------------------------------- float radiusSq = Square( m_flRadius ); // Search players first for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { if ( subjectList.Count() == MAX_HANDLED || targetList.Count() == MAX_HANDLED ) { DevMsg( "Too many entities handled by ai_relationship %s\n", GetDebugName() ); break; } CBasePlayer *pPlayer = UTIL_PlayerByIndex( i ); if ( pPlayer ) { if( IsASubject( pPlayer ) ) { if ( m_flRadius == 0.0 || GetAbsOrigin().DistToSqr( pPlayer->GetAbsOrigin() ) <= radiusSq ) subjectList.AddToTail( pPlayer ); } else if( IsATarget( pPlayer ) ) { targetList.AddToTail( pPlayer ); } } } // Search NPCs for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ ) { if ( subjectList.Count() == MAX_HANDLED || targetList.Count() == MAX_HANDLED ) { DevMsg( "Too many entities handled by ai_relationship %s\n", GetDebugName() ); break; } CAI_BaseNPC *pNPC = (g_AI_Manager.AccessAIs())[i]; if ( pNPC ) { if( IsASubject( pNPC ) ) { if ( m_flRadius == 0.0 || GetAbsOrigin().DistToSqr( pNPC->GetAbsOrigin() ) <= radiusSq ) subjectList.AddToTail( pNPC ); } else if( IsATarget( pNPC ) ) { targetList.AddToTail( pNPC ); } } } // If either list is still empty, we have a problem. if( subjectList.Count() == 0 ) { DevMsg( 2, "ai_relationship '%s' finds no subject(s) called: %s\n", GetDebugName(), STRING( m_iszSubject ) ); return; } else if ( targetList.Count() == 0 ) { DevMsg( 2, "ai_relationship '%s' finds no target(s) called: %s\n", GetDebugName(), STRING( m_target ) ); return; } // Ok, lists are populated. Apply all relationships. for ( int i = 0 ; i < subjectList.Count(); i++ ) { CBaseCombatCharacter *pSubject = subjectList[ i ]; for ( int j = 0 ; j < targetList.Count(); j++ ) { CBaseCombatCharacter *pTarget = targetList[ j ]; if ( m_iPreviousDisposition == -1 && iReverting == NOT_REVERTING ) { // Set previous disposition. m_iPreviousDisposition = pSubject->IRelationType( pTarget ); m_iPreviousRank = pSubject->IRelationPriority( pTarget ); } if ( iReverting == REVERTING_TO_PREV ) { pSubject->AddEntityRelationship( pTarget, (Disposition_t)m_iPreviousDisposition, m_iPreviousRank ); if( m_bReciprocal ) { pTarget->AddEntityRelationship( pSubject, (Disposition_t)m_iPreviousDisposition, m_iPreviousRank ); } } else if ( iReverting == REVERTING_TO_DEFAULT ) { pSubject->RemoveEntityRelationship( pTarget ); if( m_bReciprocal ) { pTarget->RemoveEntityRelationship( pSubject ); } } else if( pSubject->IRelationType(pTarget) != disposition || pSubject->IRelationPriority(pTarget) != m_iRank || HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_SUBJECT ) || HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_TARGET ) ) { // Apply the relationship to the subject pSubject->AddEntityRelationship( pTarget, (Disposition_t)disposition, m_iRank ); // Make the subject aware of the target if ( HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_SUBJECT ) ) { DiscloseNPCLocation( pSubject, pTarget ); } // Make the target aware of the subject if ( HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_TARGET ) ) { DiscloseNPCLocation( pTarget, pSubject ); } // This relationship is applied to target and subject alike if ( m_bReciprocal ) { // Apply the relationship to the target pTarget->AddEntityRelationship( pSubject, (Disposition_t)disposition, m_iRank ); } } } } }