Пример #1
0
bool CAISensorPassTarget::ContinueHoldingPosition( bool* pbCalledFindPath ) 
{ 
	// Continue holding if AI does not have a new cover or ambush dest.

	CAIWMFact factQuery;
	factQuery.SetFactType( kFact_Task );
	factQuery.SetTaskType( kTask_Cover );
	CAIWMFact* pFact = m_pAI->GetAIWorkingMemory()->FindWMFact( factQuery );
	if( !pFact )
	{
		factQuery.SetTaskType( kTask_Ambush );
		pFact = m_pAI->GetAIWorkingMemory()->FindWMFact( factQuery );
	}
	if( !( pFact && ( pFact->GetConfidence( CAIWMFact::kFactMask_TaskType ) == 1.f ) ) )
	{
		return true;
	}

	// Stop holding position if AI is scripted to go for cover.

	if( pFact->GetFactFlags() & kFactFlag_Scripted )
	{
		return false;
	}

	// Continue holding if cover dest is not valid.

	HOBJECT hNode = pFact->GetTargetObject();
	AINode* pNode = (AINode*)g_pLTServer->HandleToObject( hNode );
	if( !( pNode && pNode->IsNodeValid( m_pAI, m_pAI->GetPosition(), NULL, kThreatPos_TargetPos, kNodeStatus_Avoid ) ) )
	{
		return true;
	}

	// Continue holding if no path exists to the node.

	*pbCalledFindPath = true;
	static CAIPathNavMesh NMPath;
	if( !FindPathToNode( hNode, &NMPath ) )
	{
		return true;
	}

	// Continue holding if path crosses target's position.

	ENUM_NMPolyID ePolyTarget = GetTargetNavMeshPoly();
	if( PathIncludesPoly( NMPath, ePolyTarget ) )
	{
		AvoidNode( hNode );
		return true;
	}

	// Stop holding position!
	// We are ready to move somewhere new for cover or ambush.

	return false; 
}
Пример #2
0
HOBJECT CAIGoalFlee::FindBestNode( EnumAINodeType eNodeType )
{
	// Return the cached node if still valid.
	// This ensures an AI keeps heading to the same node if interrupted.

	if( m_hCachedBestNode )
	{
		HOBJECT hThreat = m_pAI->GetAIBlackBoard()->GetBBTargetObject();
		AINode* pNode = (AINode*)g_pLTServer->HandleToObject( m_hCachedBestNode );
		if( pNode->IsNodeValid( m_pAI, m_pAI->GetPosition(), hThreat, kThreatPos_TargetPos, m_dwNodeStatus ) )
		{
			return m_hCachedBestNode;
		}
	}

	// Default behavior.

	HOBJECT hNode = super::FindBestNode( eNodeType );
	if( hNode )
	{
		return hNode;
	}

	// Fail-safe.

	uint32 dwNodeStatus = kNodeStatus_Disabled | 
						  kNodeStatus_LockedByOther | 
						  kNodeStatus_ThreatInsideRadius;

	HOBJECT hThreat = m_pAI->GetAIBlackBoard()->GetBBTargetObject();
	CAIWMFact* pFact = m_pAI->GetAIWorkingMemory()->FindFactNodeMax( m_pAI, kNode_Cover, dwNodeStatus, m_hNode, hThreat );
	if( pFact )
	{
		return pFact->GetTargetObject();
	}
	pFact = m_pAI->GetAIWorkingMemory()->FindFactNodeMax( m_pAI, kNode_Ambush, dwNodeStatus, m_hNode, hThreat );
	if( pFact )
	{
		return pFact->GetTargetObject();
	}

	// No nodes.

	return NULL;
}
void CAIGoalUseArmoredAutonomous::CalculateGoalRelevance()
{
	// Using armored nodes requires a ranged weapon.

	if( !AIWeaponUtils::HasWeaponType( m_pAI, kAIWeaponType_Ranged, AIWEAP_CHECK_HOLSTER ) )
	{
		m_fGoalRelevance = 0.f;
		return;
	}

	// Using armored nodes require ammo to fire the ranged weapon.

	if( !AIWeaponUtils::HasWeaponType( m_pAI, kAIWeaponType_Ranged, AIWEAP_CHECK_HOLSTER ) )
	{
		m_fGoalRelevance = 0.f;
		return;
	}

	// If we are not executing the goal, and if we are already at a valid 
	// node of the correct type, then the goal is not relevant.

	if (!IsGoalInProgress())
	{
		SAIWORLDSTATE_PROP* pAtNodeProp = m_pAI->GetAIWorldState()->GetWSProp( kWSK_AtNodeType, m_pAI->m_hObject );
		if (pAtNodeProp && ( pAtNodeProp->eAINodeTypeWSValue == m_pGoalRecord->eNodeType) )
		{
			SAIWORLDSTATE_PROP* pAtNode = m_pAI->GetAIWorldState()->GetWSProp( kWSK_AtNode, m_pAI->m_hObject );
			if (pAtNode)
			{
				AINode* pNode = AINode::HandleToObject(pAtNode->hWSValue);
				if( pNode && pNode->IsNodeValid( m_pAI, m_pAI->GetPosition(), m_pAI->GetAIBlackBoard()->GetBBTargetObject(), kThreatPos_TargetPos, kNodeStatus_All ) )
				{
					m_fGoalRelevance = 0.f;
					return;
				}
			}
		}
	}

	// Default Behavior.

	super::CalculateGoalRelevance();
}
Пример #4
0
bool CAIGoalStalk::IsPlanValid()
{
	if (!super::IsPlanValid())
	{
		return false;
	}

	// Insure the stalking node is still valid.

	AINode* pNode = AINode::HandleToObject(m_hStalkingNode);
	if (!pNode)
	{
		return false;
	}

	if(!pNode->IsNodeValid( m_pAI, m_pAI->GetPosition(), m_pAI->GetAIBlackBoard()->GetBBTargetObject(), kThreatPos_TargetPos, kNodeStatus_All ) )
	{
		return false;
	}

	return true;
}
Пример #5
0
bool CAIActionAttackGrenade::ValidateContextPreconditions( CAI* pAI, CAIWorldState& wsWorldStateGoal, bool bIsPlanning )
{
	// Target is not visible.

	if( !pAI->HasTarget( kTarget_Character | kTarget_Object ) )
	{
		return false;
	}

	// AI does not have a weapon of the correct type

	if (!AIWeaponUtils::HasWeaponType(pAI, GetWeaponType(), bIsPlanning))
	{
		return false;
	}

	// AI does not have any ammo for this weapon.

	if ( !AIWeaponUtils::HasAmmo( pAI, GetWeaponType(), bIsPlanning ) )
	{
		return false;
	}

	// At a node that does not allow grenade throwing.

	bool bAtNode = false;
	bool bStraightPathCheckRequired = true;
	SAIWORLDSTATE_PROP* pProp = pAI->GetAIWorldState()->GetWSProp( kWSK_AtNode, pAI->m_hObject );
	if( pProp && pProp->hWSValue )
	{
		AINode* pNode = (AINode*)g_pLTServer->HandleToObject( pProp->hWSValue );
		if( !pNode )
		{
			return false;
		}

		if( !pNode->AllowThrowGrenades() )
		{
			return false;
		}

		if( !pNode->IsNodeValid( pAI, pAI->GetPosition(), pAI->GetAIBlackBoard()->GetBBTargetObject(), kThreatPos_TargetPos, kNodeStatus_ThreatOutsideFOV ) )
		{
			return false;
		}

		bStraightPathCheckRequired = pNode->RequiresStraightPathToThrowGrenades();
		bAtNode = true;
	}

	// Target is not in range.

	if (!AIWeaponUtils::IsInRange(pAI, GetWeaponType(), bIsPlanning))
	{
		return false;
	}

	// Someone else has thrown a grenade recently.

	CAIWMFact factQuery;
	factQuery.SetFactType(kFact_Knowledge);
	factQuery.SetKnowledgeType(kKnowledge_NextGrenadeTime);
	CAIWMFact* pFact = g_pAIWorkingMemoryCentral->FindWMFact(factQuery);
	if(pFact && g_pLTServer->GetTime() < pFact->GetTime() )
	{
		return false;
	}

	// Throw at the last known position.

	CAIWMFact factTargetQuery;
	HOBJECT hTarget = pAI->GetAIBlackBoard()->GetBBTargetObject();
	factTargetQuery.SetFactType( kFact_Character );
	factTargetQuery.SetTargetObject( hTarget );
	pFact = pAI->GetAIWorkingMemory()->FindWMFact( factTargetQuery );
	if( !pFact )
	{
		return false;
	}
	LTVector vTargetPos = pFact->GetPos();

	/***
	// Only throw a grenade when not at a node when there is a 
	// straight path to the target.  This is to ensure the 
	// grenade won't bounce back and kill the thrower.

	if( bStraightPathCheckRequired )
	{
		if( !g_pAIPathMgrNavMesh->StraightPathExists( pAI, pAI->GetCharTypeMask(), pAI->GetPosition(), vTargetPos, pAI->GetLastNavMeshPoly(), 0.f ) )
		{
			return false;
		}
	}
	***/

	/***
	// Don't throw if someone is closer to the target than me, 
	// because I might hit them!

	if( pAI != g_pCharacterMgr->FindNearestAIAlly( pAI, vTargetPos ) )
	{
		return false;
	}
	***/

	// Get the grenade explosion radius.

	HAMMO hAmmo = AIWeaponUtils::GetWeaponAmmo( pAI, GetWeaponType(), bIsPlanning );
	HAMMODATA hAmmoData = g_pWeaponDB->GetAmmoData(hAmmo,true);
	float fRadius = g_pWeaponDB->GetFloat( hAmmoData, WDB_AMMO_fAreaDamageRadius );
	fRadius *= 1.2f;

	// Don't throw if we're in the radius!

	if( pAI->GetPosition().DistSqr( vTargetPos ) < fRadius * fRadius )
	{
		return false;
	}

	// Don't throw if an ally is in the blast radius.

	if( g_pCharacterMgr->FindAIAllyInRadius( pAI, vTargetPos, fRadius ) )
	{
		return false;
	}

/***
	// Don't throw grenade at allies.

	CTList<CCharacter*> lstChars;
	if( g_pCharacterMgr->FindCharactersWithinRadius( &lstChars, vTargetPos, fRadius, CCharacterMgr::kList_AIs ) )
	{
		// Iterate over characters in grenade's radius.

		CCharacter** pCur = lstChars.GetItem(TLIT_FIRST);
		while( pCur )
		{
			CCharacter* pChar = (CCharacter*)*pCur;
			pCur = lstChars.GetItem(TLIT_NEXT);

			// Skip the AI himself.

			if( pChar == pAI )
			{
				continue;
			}

			// Action is invalid if grenade could hit someone 
			// that the AI does not hate.

			if( g_pCharacterDB->GetStance( pAI->GetAlignment(), pChar->GetAlignment() ) != kCharStance_Hate )
			{
				return false;
			}
		}
	}
***/

	// Throw a grenade.

	return true;
}
Пример #6
0
void CAIGoalGoto::CalculateGoalRelevance()
{
	// Wait until after teleporting to Goto.
	// This is necessary due to update ordering between CAI and CCharacter.

	if( m_pAI->GetTeleportTriggerState() != eTeleporTriggerStateNone )
	{
		m_fGoalRelevance = 0.f;
		return;
	}

	// Bail if we have no Goto task.

	CAIWMFact factQuery;
	factQuery.SetFactType( kFact_Task );
	factQuery.SetTaskType( m_eTaskType );
	CAIWMFact* pFact = m_pAI->GetAIWorkingMemory()->FindWMFact( factQuery );
	if( pFact && 
		pFact->IsSet( CAIWMFact::kFactMask_TargetObject ) &&
		pFact->GetTargetObject() &&
		( pFact->GetConfidence( CAIWMFact::kFactMask_TaskType ) == 1.f ) )
	{
		// Bail if node is disabled or invalid.

		HOBJECT hNode = pFact->GetTargetObject();
		if( IsAINode( hNode ) )
		{
			// Node is disabled.

			AINode* pNode = (AINode*)g_pLTServer->HandleToObject( hNode );
			if( pNode->IsNodeDisabled() )
			{
				hNode = NULL;
				m_fGoalRelevance = 0.f;
				return;
			}

			// Node is invalid.

			if( m_bCheckNodeValidity &&
				!pNode->IsNodeValid( m_pAI, m_pAI->GetPosition(), NULL, kThreatPos_TargetPos, kNodeStatus_All ) )
			{
				hNode = NULL;
				m_fGoalRelevance = 0.f;
				return;
			}
		}

		// New node requested.

		if( m_NodeCurrent.eFactID != pFact->GetFactID() )
		{
			m_NodePending.hNode = hNode;
			m_NodePending.eFactID = pFact->GetFactID();
			m_NodePending.bTaskIsScripted = ( pFact->GetFactFlags() & kFactFlag_Scripted ) ? true : false;
		}
		m_fGoalRelevance = m_pGoalRecord->fIntrinsicRelevance;
		return;
	}

	// There is no Goto task.

	m_fGoalRelevance = 0.f;
}
Пример #7
0
	int operator()(CAIWMFact* pFact)
	{
		// Ignore facts that are not node facts.
		// Ignore node facts with the wrong node type.
		// Ignore node facts whose object matches the hExclude.

		if( ( pFact->GetFactType() != kFact_Node ) ||
			( pFact->GetNodeType() != kNode_Stalk ))
		{
			return 0;
		}

		AINode* pNode = AINode::HandleToObject( pFact->GetTargetObject() );
		if( !pNode )
		{
			return 0;
		}

		// Bail if node is locked by someone else, disabled, or timed out.

		// TODO: Handle the AI locking the node.  This can work when code to 
		// handle an invalid node is written.
		if (pNode->GetHOBJECT() == m_hIgnoreStalkingNode)
		{
			return false;
		}

		if (pNode->IsNodeLocked()/* && pNode->GetLockingAI() != m_pAI->GetHOBJECT()*/)
		{
			return false;
		}

		if( pNode->IsNodeDisabled() || pNode->IsNodeTimedOut() )
		{
			return false;
		}

		// Require the AI be in the radius or region

		if (!pNode->IsAIInRadiusOrRegion( m_pAI, m_pAI->GetPosition(), 1.f ))
		{
			return 0;
		}

		// If AI is aware of a threat, ignore nodes that are invalid.

		if( m_hThreat && 
			( !pNode->IsNodeValid( m_pAI, m_pAI->GetPosition(), m_hThreat, kThreatPos_TargetPos, kNodeStatus_All ^ kNodeStatus_ThreatOutsideFOV) ) )
		{
			return 0;
		}

		// Failed to find a valid destination position.

		LTVector vDestination;
		if (!pNode->GetDestinationPosition(m_pAI, m_pAI->GetAIBlackBoard()->GetBBTargetPosition(), vDestination))
		{
			return 0;
		}

		// The stalking position is further from the AIs goal than the AI 
		// currently is (don't run backwards to stalk).

		float flNodeDestToAIDestDistSqr = vDestination.DistSqr(m_pAI->GetAIBlackBoard()->GetBBTargetReachableNavMeshPosition());
		if (flNodeDestToAIDestDistSqr > m_flDistanceToDestinationSqr)
		{
			return 0;
		}

		// Node is behind the AI.

		if (0 > m_pAI->GetForwardVector().Dot( vDestination - m_pAI->GetPosition()))
		{
			return 0;
		}

		// Already found a closer node.

		float flDistanceFromAISqr = vDestination.DistSqr(m_pAI->GetPosition());
		if (flDistanceFromAISqr > m_flBestDistanceFromAISqr)
		{
			return 0;
		}

		m_vBestPosition = vDestination;
		m_flBestDistanceFromAISqr = flDistanceFromAISqr;
		m_pBestFact = pFact;

		return 0;
	}
Пример #8
0
void CAIGoalStalk::CalculateGoalRelevance()
{
	// The target MUST be a character, regardless of current goal status.

	if ( !m_pAI->HasTarget( kTarget_Character ) )
	{
		m_fGoalRelevance = 0.f;
		return;
	}

	// Goal in progress, and the node is still valid.

	if ( m_pAI->GetGoalMgr()->IsCurGoal(this) )
	{
		if (!IsWSSatisfied(m_pAI->GetAIWorldState()))
		{
			AINode* pNode = AINode::HandleToObject(m_hStalkingNode);
			if (pNode)
			{
				if (pNode->IsNodeValid(m_pAI, m_pAI->GetPosition(), m_pAI->GetAIBlackBoard()->GetBBTargetObject(), kThreatPos_TargetPos, kNodeStatus_All))
				{
					m_fGoalRelevance = m_pGoalRecord->fIntrinsicRelevance;
					return;
				}
			}
		}
	}

	// Damaged recently

	CAIWMFact factQuery;
	factQuery.SetFactType(kFact_Damage);
	CAIWMFact* pDamagedFact = m_pAI->GetAIWorkingMemory()->FindWMFact( factQuery );
	if( pDamagedFact 
		&& ( DidDamage(m_pAI, pDamagedFact) )
		&& ( pDamagedFact->GetUpdateTime() < g_pLTServer->GetTime() - 4.f ) )
	{
		m_fGoalRelevance = 0.f;
		return;
	}

	// No target object

	if (NULL == m_pAI->GetAIBlackBoard()->GetBBTargetObject())
	{
		m_fGoalRelevance = 0.f;
		return;
	}

	// Enemy is too close (note that this NOT the destination, this is the 
	// threat -- AIs next to their enemies should not attempt to stalk)

	float flAIToAIDestDistSqr = m_pAI->GetPosition().DistSqr(m_pAI->GetAIBlackBoard()->GetBBTargetReachableNavMeshPosition());
	if ( flAIToAIDestDistSqr < kThreatTooCloseThresholdSqr)
	{
		m_fGoalRelevance = 0.f;
		return;
	}

	// Stalking is relevent when the AI is in the process of going somewhere

	if( m_pAI->GetAIBlackBoard()->GetBBDestStatus() != kNav_Set )
	{
		m_fGoalRelevance = 0.f;
		return;
	}

	// Failed to find a potential stalking node.

	StalkingNodeFinder finder(m_pAI, m_pAI->GetAIBlackBoard()->GetBBTargetObject(), m_hPreviousStalkingNode, flAIToAIDestDistSqr);
	m_pAI->GetAIWorkingMemory()->CollectFact(finder);
	CAIWMFact* pFact = finder.GetFact();
	if (!pFact)
	{
		m_fGoalRelevance = 0.f;
		return;
	}

	m_vPendingStalkingPosition = finder.GetPosition();
	m_hPendingStalkingNode = pFact->GetTargetObject();
	m_fGoalRelevance = m_pGoalRecord->fIntrinsicRelevance;
}
Пример #9
0
void CAIGoalFlee::CalculateGoalRelevance()
{
	// Don't flee if we have not yet seen our target.

	if( m_pAI->GetAIBlackBoard()->GetBBTargetLastVisibleTime() == 0.f )
	{
		m_fGoalRelevance = 0.f;
		return;
	}

	// Maintain relevance if goal was already active, and animation
	// is locked.  (e.g. while AI is mounting a node).

	if( m_hNode && m_pAI->GetAnimationContext()->IsLocked() )
	{
		m_fGoalRelevance = m_pGoalRecord->fIntrinsicRelevance;
		return;
	}

	// Always try to flee when target is unreachable.

	LTVector vTargetPos = m_pAI->GetAIBlackBoard()->GetBBTargetPosition();
	if( !g_pAIPathMgrNavMesh->HasPath( m_pAI, m_pAI->GetCharTypeMask(), vTargetPos ) )
	{
		super::CalculateGoalRelevance();
		return;
	}

	// Always try to flee when target exist AI's guard radius.

	if( !m_pAI->GetAnimationContext()->IsLocked() )
	{
		CAIWMFact factQueryGuard;
		factQueryGuard.SetFactType(kFact_Node);
		factQueryGuard.SetNodeType(kNode_Guard);
		CAIWMFact* pFactGuard = m_pAI->GetAIWorkingMemory()->FindWMFact( factQueryGuard );
		if( pFactGuard )
		{
			AINodeGuard* pGuardNode = (AINodeGuard*)g_pLTServer->HandleToObject( pFactGuard->GetTargetObject() );
			if( pGuardNode && pGuardNode->IsAIInRadiusOrRegion( m_pAI, m_pAI->GetPosition(), 1.f ) )
			{
				ENUM_NMPolyID ePoly = m_pAI->GetAIBlackBoard()->GetBBTargetTrueNavMeshPoly();
				if( pGuardNode && !pGuardNode->IsPosInRadiusOrRegion( vTargetPos, ePoly, 1.f ) )
				{
					super::CalculateGoalRelevance();
					return;
				}
			}
		}
	}

	// We may be at some node.

	HOBJECT hNode = NULL;
	SAIWORLDSTATE_PROP* pProp = m_pAI->GetAIWorldState()->GetWSProp( kWSK_AtNode, m_pAI->m_hObject );
	if( pProp )
	{
		hNode = pProp->hWSValue;
	}

	// Goal has no relevance if we are already at a node, and this goal is not currently active.

	if( hNode && !m_hNode )
	{
		m_fGoalRelevance = 0.f;
		return;
	}

	// Goal has no relevance if we are already at an invalid node.

	if( hNode )
	{
		AINode* pNode = (AINode*)g_pLTServer->HandleToObject( hNode );
		if( pNode && ( !pNode->IsNodeValid( m_pAI, m_pAI->GetPosition(), m_pAI->GetAIBlackBoard()->GetBBTargetObject(), kThreatPos_TargetPos, m_dwNodeStatus ) ) )
		{
			m_fGoalRelevance = 0.f;
			return;
		}
	}

	// Goal is only relevant if we have the desire to retreat or flee.

	bool bFlee = false;
	CAIWMFact factQuery;
	factQuery.SetFactType(kFact_Desire);
	factQuery.SetDesireType(kDesire_Retreat);
	CAIWMFact* pFact = m_pAI->GetAIWorkingMemory()->FindWMFact( factQuery );
	if( pFact )
	{
		bFlee = true;
	}
	else {
		factQuery.SetDesireType(kDesire_Flee);
		pFact = m_pAI->GetAIWorkingMemory()->FindWMFact( factQuery );
		if( pFact )
		{
			bFlee = true;
		}
	}

	// Default calculation.

	if( bFlee )
	{
		super::CalculateGoalRelevance();
	}

	// Do not flee.

	else 
	{
		m_fGoalRelevance = 0.f;
	}
}