Exemplo n.º 1
0
bool AINodeValidatorPathBlocked::Evaluate( uint32 dwFilteredStatusFlags, const LTVector& vNodePos, const LTVector& vAIPos, const LTVector& vThreatPos ) const
{
	// Threat blocking path.

	if( dwFilteredStatusFlags & kNodeStatus_ThreatBlockingPath )
	{
		// Check if the threat is too close to the AI,
		// and is blocking the path to the node.

		if ( vAIPos.DistSqr(vThreatPos) < g_pAIDB->GetAIConstantsRecord()->fThreatTooCloseDistanceSqr )
		{
			LTVector vToThreat = vThreatPos - vAIPos;
			LTVector vToNode = vNodePos - vAIPos;

			if( vToThreat.Dot( vToNode ) > c_fFOV60 )
			{
				return false;
			}
		}
	}

	return true;
}
Exemplo n.º 2
0
LTBOOL FindGrenadeDangerPosition(const LTVector& vPos, LTFLOAT fDangerRadiusSqr, LTVector* pvDangerPos, CGrenade** ppGrenadeDanger)
{
	_ASSERT(pvDangerPos);

	CGrenade** ppGrenade = g_lstGrenades.GetItem(TLIT_FIRST);
	while ( ppGrenade && *ppGrenade )
	{
		CGrenade* pGrenade = *ppGrenade;

		LTVector vGrenadePosition;
		g_pLTServer->GetObjectPos(pGrenade->m_hObject, &vGrenadePosition);

		if ( vPos.DistSqr(vGrenadePosition) < fDangerRadiusSqr )
		{
			*ppGrenadeDanger = pGrenade;
			*pvDangerPos = vGrenadePosition;
			return LTTRUE;
		}
		
		ppGrenade = g_lstGrenades.GetItem(TLIT_NEXT);
	}

	return LTFALSE;
}
Exemplo n.º 3
0
bool AINodeValidatorPlayerOnNode::Evaluate( uint32 dwFilteredStatusFlags, CAI* pAI, const LTVector& vNodePos ) const
{
	// Node is always valid if there is no AI to consider.

	if( !pAI )
	{
		return true;
	}

	// Player is standing on the node.

	if( dwFilteredStatusFlags & kNodeStatus_PlayerOnNode )
	{
		float fMinDist;
		uint32 iPlayer = 0;
		LTVector vPlayerDims;
		LTVector vPlayerPos;
		CPlayerObj* pPlayer;
		while( true )
		{
			// Check the next Player, if others exist.

			pPlayer = g_pCharacterMgr->FindPlayer( iPlayer );
			if( !pPlayer )
			{
				return true;
			}
			++iPlayer;

			// Bail if we don't like Players.

			if( g_pCharacterDB->GetStance( pAI->GetAlignment(), pPlayer->GetAlignment() ) != kCharStance_Like )
			{
				return true;
			}

			// Node is above or below the Player's cylinder.

			g_pLTServer->GetObjectPos( pPlayer->m_hObject, &vPlayerPos );
			g_pPhysicsLT->GetObjectDims( pPlayer->m_hObject, &vPlayerDims );
			if( ( vPlayerPos.y - vPlayerDims.y > vNodePos.y ) ||
				( vPlayerPos.y + vPlayerDims.y < vNodePos.y ) )
			{
				continue;
			}

			// Pad the Player's radius by 100%.

			fMinDist = pPlayer->GetRadius();
			fMinDist *= 2.f;

			// Player is too close to the Node.

			vPlayerPos.y = vNodePos.y;
			if( vPlayerPos.DistSqr( vNodePos ) < fMinDist * fMinDist )
			{
				return false;
			}
		}
	}

	return true;
}
Exemplo n.º 4
0
// Tries everything it can think of to reject this object intersection.
// If it does intersect and is closer than the current best world intersection
// then it replaces the current one.
inline bool i_HandlePossibleIntersection(const LTVector& Point1, const LTVector& Point2, LTObject *pServerObj)
{
    // Quick sphere test.
    if (i_QuickSphereTest(pServerObj)) 
	{
        // Ok, filter if necessary.
        if (g_pCurQuery->m_FilterFn && 
            !g_pCurQuery->m_FilterFn((HOBJECT)pServerObj, g_pCurQuery->m_pUserData))
        {
            // They said to ignore it..
        }
        else 
		{
            // If it's a WorldModel, add it to the list to be tested later.
            // You can't treat it like a solid box here because a ray could go
            // right through all its geometry.

            // [kls 5/16/00 Always do full intersection tests on world models
            // so we get the correct hpoly information
            // if (HasWorldModel(pServerObj) && !(pServerObj->m_Flags & FLAG_BOXPHYSICS))
            
            if (HasWorldModel(pServerObj)) 
			{
				return i_TestWorldModel(pServerObj->ToWorldModel());
            }
            else 
			{
                // Bounding box test...
				LTVector testPt;
				LTPlane testPlane;
                if (i_BoundingBoxTest(Point1, Point2, pServerObj, &testPt, &testPlane)) 
				{
                    // Is this intersection closer than the current best?
                    float distToIntersectionSqr = testPt.DistSqr(g_pCurQuery->m_From);
                    
                    if (g_pIntersection) 
					{
                        if (distToIntersectionSqr < g_IntersectionBestDistSqr) 
						{
                            // Do we care about model OBBs?
							if(g_bProcessModelObbs)
							{
                                // Is this object a model?
                                if(IsModel(pServerObj))
                                {
                                    ModelInstance *pModel =	pServerObj->ToModel();
                                    
                                    // Does this object want to expose it's OBBs?                                    
                                    if(pServerObj->m_Flags2 & FLAG2_USEMODELOBBS)
                                    {                                        
                                        // Does this model have OBBS? 
                                        if(pModel->IsCollisionObjectsEnabled())                                      
                                        {              
                                            // Then test the OBBs
                                            return i_TestModelOBBS(pModel);
                                        }else
                                        {
                                            // If this object has specified OBBs enabled but is 
                                            // not equipt for model obbs, then return no collision                                        
                                            return false;
                                        }
                                    }                                                                        
                                }
							}
							//else
                            return UseThisObject(pServerObj, distToIntersectionSqr, testPlane, testPt, INVALID_HPOLY, INVALID_MODEL_NODE);
                        }
                    }
                    else 
					{
                        //USE_THIS_OBJECT(pServerObj, distToIntersectionSqr, testPlane, testPt, INVALID_HPOLY);
                        //return true;
                        return UseThisObject(pServerObj, distToIntersectionSqr, testPlane, testPt, INVALID_HPOLY, INVALID_MODEL_NODE);
                    }
                }
            }
        }
    }

    return false;
}
bool CAIActionAttackLungeUncloaked::ValidateContextPreconditions( CAI* pAI, CAIWorldState& wsWorldStateGoal, bool bIsPlanning )
{
	// AI doesn't have a target.

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

	// Target is not visible.

	if( !pAI->GetAIBlackBoard()->GetBBTargetVisibleFromWeapon() )
	{
		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;
	}

	// Someone else is lunging.  Only one AI may lunge at a time.

	CAIWMFact factQuery;
	factQuery.SetFactType( kFact_Knowledge );
	factQuery.SetKnowledgeType( kKnowledge_Lunging );
	CAIWMFact* pFact = g_pAIWorkingMemoryCentral->FindWMFact(factQuery);
	if( pFact )
	{
		// Clear records of dead AI.

		if( IsDeadAI( pFact->GetSourceObject() ) )
		{
			g_pAIWorkingMemoryCentral->ClearWMFacts( factQuery );
		}
		else return false;
	}

	// Bail if the Action's SmartObject record does not exist.

	AIDB_SmartObjectRecord* pSmartObjectRecord = g_pAIDB->GetAISmartObjectRecord( m_pActionRecord->eSmartObjectID );
	if( !pSmartObjectRecord )
	{
		return false;
	}


	// Someone has lunged too recently.

	if( pSmartObjectRecord->fTimeout > 0.f )
	{
		factQuery.SetFactType( kFact_Knowledge );
		factQuery.SetKnowledgeType( kKnowledge_NextLungeTime );
		pFact = g_pAIWorkingMemoryCentral->FindWMFact(factQuery);
		if( pFact && ( pFact->GetTime() > g_pLTServer->GetTime() ) )
		{
			return false;
		}
	}

	// Bail if the AI does not have the desire to lunge.
	// The desire indicates the max range of the lunge.

	CAIWMFact factDesireQuery;
	factDesireQuery.SetFactType( kFact_Desire );
	factDesireQuery.SetDesireType( kDesire_Lunge );
	CAIWMFact* pDesireFact = pAI->GetAIWorkingMemory()->FindWMFact( factDesireQuery );
	if( !pDesireFact )
	{
		return false;
	}

	// Target must be in range.

	LTVector vTarget = pAI->GetAIBlackBoard()->GetBBTargetPosition();
	float fDistSqr = vTarget.DistSqr( pAI->GetPosition() );

	// Target too close.

	if( fDistSqr < pSmartObjectRecord->fMinDist * pSmartObjectRecord->fMinDist )
	{
		return false;
	}

	// Target too far.

	float fMaxDist = GetLungeMaxDist( pAI, pDesireFact );
	if( fDistSqr > fMaxDist * fMaxDist )
	{
		return false;
	}

	// No straight path to the target.

	LTVector vDir = vTarget - pAI->GetPosition();
	vDir.Normalize();
	LTVector vDest = pAI->GetPosition() + ( vDir * ( fMaxDist + 50.f ) );
	if( !g_pAIPathMgrNavMesh->StraightPathExists( pAI, pAI->GetCharTypeMask(), pAI->GetPosition(), vDest, pAI->GetAIBlackBoard()->GetBBTargetReachableNavMeshPoly(), pAI->GetRadius() ) )
	{
		return false;
	}

	// Lunge!

	return true;
}
Exemplo n.º 6
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;
	}
Exemplo n.º 7
0
bool AINavMeshLinkPlayer::FindNearestNavMeshPos( CAI* pAI, const LTVector& vPos, LTVector* pvNavMeshPos, ENUM_NMPolyID* peNavMeshPoly )
{
	// Sanity check.

	if( !( pAI && pvNavMeshPos && peNavMeshPoly ) )
	{
		return false;
	}

	// Bail if Link's poly is invalid.

	CAINavMeshPoly* pPoly = g_pAINavMesh->GetNMPoly( m_eNMPolyID );
	if( !pPoly )
	{
		return false;
	}

	// Iterate over Link's edges, searching for edge nearest 
	// to the specified position.

	ENUM_NMPolyID eNeighborPoly;
	CAINavMeshEdge* pEdge;
	CAINavMeshEdge* pEdgeNearest = NULL;
	float fDistSqr;
	float fMinDistSqr = FLT_MAX;
	uint32 cEdges = pPoly->GetNumNMPolyEdges();
	for( uint32 iEdge=0; iEdge < cEdges; ++iEdge )
	{
		// Skip edge if doesn't exist.

		pEdge = pPoly->GetNMPolyEdge( iEdge );
		if( !pEdge )
		{
			continue;
		}

		// Skip edge if AI cannot pathfind to the neighboring poly.

		eNeighborPoly = ( pEdge->GetNMPolyIDA() != m_eNMPolyID ) ? pEdge->GetNMPolyIDA() : pEdge->GetNMPolyIDB();
		if( ( eNeighborPoly == kNMPoly_Invalid ) ||
			( !g_pAIPathMgrNavMesh->HasPath( pAI, pAI->GetCharTypeMask(), eNeighborPoly ) ) )
		{
			continue;
		}

		// Keep track of the edge nearest to the specified position.

		fDistSqr = vPos.DistSqr( pEdge->GetNMEdgeMidPt() );
		if( fDistSqr < fMinDistSqr )
		{
			fMinDistSqr = fDistSqr;
			pEdgeNearest = pEdge;
		}
	}

	// Bail if no valid edge was found.

	if( !pEdgeNearest )
	{
		return false;
	}

	// Return success.

	if( FindNearestPointOnLine( pEdgeNearest->GetNMEdge0(), pEdgeNearest->GetNMEdge1(), vPos, pvNavMeshPos ) )
	{
		// Push the point a small amount out of the link.
		
		LTVector vDir = *pvNavMeshPos - vPos;
		vDir.Normalize();
		*pvNavMeshPos += vDir * 1.f;

		*peNavMeshPoly = ( pEdgeNearest->GetNMPolyIDA() != m_eNMPolyID ) ? pEdgeNearest->GetNMPolyIDA() : pEdgeNearest->GetNMPolyIDB();
		return true;
	}

	// No intersection found.

	return false;
}
Exemplo n.º 8
0
bool CCamWobbleFX::Update(float tmFrameTime)
{
	// Base class update first
	
	if (!CBaseFX::Update(tmFrameTime)) 
		return false;

	// Return out if we have shutdown

	if (IsShuttingDown()) 
		return true;

	if (!g_bAppFocus)
	{
		return true;
	}

	LTVector	vCurCamPos;
	LTVector	vObjPos;
	
	// Retrieve the current position of the camera and get the distance to it

	m_pLTClient->GetObjectPos(m_hCamera, &vCurCamPos);
	
	if( m_hParent )
	{
		m_pLTClient->GetObjectPos( m_hParent, &vObjPos );
	}
	else
	{
		vObjPos = m_vCreatePos;
	}

	LTFLOAT	fDistSqrd = vObjPos.DistSqr( vCurCamPos );
	LTFLOAT	fFallOff;

	// Figure out the fall off of the shaking based on the inner and outer radii...

	if( fDistSqrd > GetProps()->m_fOuterDistSqrd )
	{
		return LTTRUE;
	}
	else if( fDistSqrd <= GetProps()->m_fInnerDistSqrd )
	{
		fFallOff = 1.0f;
	}
	else
	{
		fFallOff = 1 - ((fDistSqrd - GetProps()->m_fInnerDistSqrd) / (GetProps()->m_fOuterDistSqrd - GetProps()->m_fInnerDistSqrd));
	}

	// Compute the FOV offsets

	float fLen = GetProps()->m_tmLifespan / GetProps()->m_fPeriod;

	float fVal = fmodf(m_tmElapsed, fLen);

	float fRadVal = (MATH_CIRCLE / fLen) * fVal;
	
	float xOff = m_xFovAnchor + ((float)sin(fRadVal) * GetProps()->m_xMultiplier * fFallOff);
	float yOff = m_yFovAnchor + ((float)cos(fRadVal) * GetProps()->m_yMultiplier * fFallOff);

	m_pLTClient->SetCameraFOV(m_hCamera, xOff, yOff);

	// Success !!

	return true;
}
Exemplo n.º 9
0
void CCharacterHitBox::Update()
{
	AIASSERT( m_pHitBoxUser, m_hObject, "Called with NULL HitBoxUser" );
	AIASSERT( m_hModel, m_hObject, "Called with NULL m_hModel" );
	AIASSERT( m_hObject, m_hObject, "Called with NULL m_hObject" );
	if (!m_hModel || !m_hObject)
	{
		return;
	}

	// Position to move to...
	LTVector vPos;
	bool bUpdateClient = false;

	// KLS 1/23/04 - Follow the visibility node on our model if specified...

	if (m_bFollowVisNode)
	{
		// Get the model's vis node...
		
		HMODELNODE hNode;
		if ( LT_OK == g_pModelLT->GetPhysicsVisNode(m_hModel, hNode) )
		{
			LTTransform tf;

			if ( LT_OK == g_pModelLT->GetNodeTransform(m_hModel, hNode, tf, true) )
			{
				vPos = tf.m_vPos;
	
				// KLS 5/3/04 - If we're following the model's vis node, we want to move
				// the model to follow us...

				LTVector vModelPos;
				g_pLTServer->GetObjectPos(m_hModel, &vModelPos);

				if (vPos.DistSqr(vModelPos) > 0.1f)
				{
					g_pLTServer->SetObjectPos(m_hModel, vPos);
				}
			}
		}
	}
	else  // Use the model's position...
	{
		// Get current model position...
		g_pLTServer->GetObjectPos(m_hModel, &vPos);

		// Make sure the hit box offset is relative to the model...
		
		LTRotation rRot;
		g_pLTServer->GetObjectRotation( m_hModel, &rRot );
		vPos += (rRot * m_vOffset);
	}

	// Get the hitbox's position...
	LTVector vMyPos;
	g_pLTServer->GetObjectPos(m_hObject, &vMyPos);


	// Only move the hitbox if it isn't close to the target position...

	if (vPos.DistSqr(vMyPos) > 0.1)
	{
		bUpdateClient = true;
		g_pLTServer->SetObjectPos(m_hObject, vPos);
 	}

	if( (m_bAnimControlsDims || m_bAnimControlsOffset) && (m_hControllingAnim != INVALID_ANI) )
	{
		HMODELANIM hCurAnim = INVALID_ANI;
		if( LT_OK == g_pModelLT->GetCurAnim( m_hModel, MAIN_TRACKER, hCurAnim ))
		{
			if( hCurAnim != m_hControllingAnim )
			{
				// We changed animations from our controlling anim so default our dims and offset...

				// Set offset first since SetDimsToModel() will update the client
				SetOffset( LTVector(0,0,0) );
				SetDimsToModel();

				// The animation is no longer controlling us...

				m_bAnimControlsDims = m_bAnimControlsOffset = false;
				m_hControllingAnim = INVALID_ANI;
			}	
		}
	}
	
	// Make sure the hit box is at least at the minimum dims...

	LTVector vDims;
	g_pPhysicsLT->GetObjectDims( m_hObject, &vDims );

	if( vDims.x < HB_DIMS_MIN_XZ ||
		vDims.z < HB_DIMS_MIN_XZ )
	{
		vDims.x = vDims.z = HB_DIMS_MIN_XZ;
		g_pPhysicsLT->SetObjectDims( m_hObject, &vDims, 0 );
		bUpdateClient = true;

	}

	if( vDims.y < HB_DIMS_MIN_Y	)
	{
		vDims.y = HB_DIMS_MIN_Y;
		g_pPhysicsLT->SetObjectDims( m_hObject, &vDims, 0 );
		bUpdateClient = true;

	}

	if (bUpdateClient)
	{
		m_pHitBoxUser->UpdateClientHitBox();
	}

	// See if we should show our model node radii...

#ifndef _FINAL
	float fShowNodeRadii = (g_vtShowNodeRadii.GetFloat() ? (IsPlayer(m_hModel) ? g_vtShowPlayerNodeRadii.GetFloat() : 1.0f) : 0.0f);
	if (fShowNodeRadii)
	{
		UpdateNodeRadiusModels();
	}
	else
	{
		RemoveNodeRadiusModels();
	}
#endif
}
Exemplo n.º 10
0
void CAIGoalCharge::CalculateGoalRelevance()
{
	// AI doesn't have a target.

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

	// No relevance if AI does not have a deisre to lunge.
	// The desire indicates the max range of the lunge.

	CAIWMFact factDesireQuery;
	factDesireQuery.SetFactType( kFact_Desire );
	factDesireQuery.SetDesireType( kDesire_Lunge );
	CAIWMFact* pDesireFact = m_pAI->GetAIWorkingMemory()->FindWMFact( factDesireQuery );
	if( !pDesireFact )
	{
		m_fGoalRelevance = 0.f;
		return;
	}

	// Someone has lunged too recently.

	CAIWMFact factQuery;
	factQuery.SetFactType( kFact_Knowledge );
	factQuery.SetKnowledgeType( kKnowledge_NextLungeTime );
	CAIWMFact* pFact = g_pAIWorkingMemoryCentral->FindWMFact(factQuery);
	if( pFact && ( pFact->GetTime() > g_pLTServer->GetTime() ) )
	{
		m_fGoalRelevance = 0.f;
		return;
	}

	// Target must be in range.

	LTVector vTarget = m_pAI->GetAIBlackBoard()->GetBBTargetPosition();
	float fDistSqr = vTarget.DistSqr( m_pAI->GetPosition() );

	// Target too far.

	float fMaxDist = pDesireFact->GetRadius();
	if( fDistSqr > fMaxDist * fMaxDist )
	{
		m_fGoalRelevance = 0.f;
		return;
	}

	// No straight path to the target.

	if( !g_pAIPathMgrNavMesh->StraightPathExists( m_pAI, m_pAI->GetCharTypeMask(), m_pAI->GetPosition(), vTarget, m_pAI->GetAIBlackBoard()->GetBBTargetReachableNavMeshPoly(), 0.f ) )
	{
		m_fGoalRelevance = 0.f;
		return;
	}

	// Default handling from KillEnemy.

	super::CalculateGoalRelevance();
}
Exemplo n.º 11
0
void CAIMovement::AvoidDynamicObstacles(LTVector* pvNewPos, EnumAnimMovement eMovementType)
{
	LTFLOAT fRadius = 128.f;
	LTFLOAT fRadiusSqr = fRadius * fRadius;

	LTVector vMyPos = m_pAI->GetPosition();

	// Calculate the horizontal velocity.

	LTVector vVel = *pvNewPos - vMyPos;
	vVel.y = 0.f;

	// Bail if no velocity.

	if( ( vVel.x == 0.f ) && ( vVel.z == 0.f ) )
	{
		return;
	}

	LTFLOAT fMag = vVel.Mag();

	LTVector vTotalForce(0.f, 0.f, 0.f);
	LTVector vObstaclePos;
	LTFLOAT fDistSqr;
	LTFLOAT fForce;
	LTVector vForce;

	CTList<CCharacter*>* lstChars	= LTNULL;
	CCharacter** pCur				= LTNULL;

	// Iterate over all characters in the world.

	int cCharLists = g_pCharacterMgr->GetNumCharacterLists();
	for ( int iList = 0 ; iList < cCharLists ; ++iList )
	{
		lstChars = g_pCharacterMgr->GetCharacterList(iList);

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

			// Ignore myself.

			if( pChar == m_pAI )
			{
				continue;
			}

			// Ignore characters that are too close to our dest.
			// The pathfinding system requires AIs to reach waypoints.

			g_pLTServer->GetObjectPos( pChar->m_hObject, &vObstaclePos );
			if( vObstaclePos.DistSqr( m_vDest ) <= fRadiusSqr )
			{
				continue;
			}

			// Only characters within radius have forces that affect me.

			fDistSqr = vObstaclePos.DistSqr( vMyPos );
			if( fDistSqr >= fRadiusSqr )
			{
				continue;
			}

			// Calculate the force vector from the obstacle to myself.

			fForce = fRadius - (LTFLOAT)sqrt( fDistSqr );
			fForce /= fRadius;
			fForce *= fForce;
			fForce *= ( 2.f * fMag );

			vForce = vMyPos - vObstaclePos;
			vForce.y = 0.f;
			vForce.Normalize();
			vForce *= fForce;

			// Accumulate the total force from all obstacles.

			vTotalForce += vForce;			
		}
	}

	// Bail if no forces are affecting me.

	if( ( vTotalForce.x == 0.f ) && ( vTotalForce.z == 0.f ) )
	{
		return;
	}

	// Calculate a new velocity vector.

	LTVector vNewVel = vVel + vTotalForce;

	// Constrain velocity so that is never deviates more than 
	// 90 degrees in either direction.  This prevents AIs from ever
	// reversing their direction when the forces are stronger than
	// the initial velocity.

	if( vNewVel.Dot( vVel ) < 0.f )
	{
		vVel.Normalize();
		LTVector vUp( 0.f, 1.f, 0.f );
		LTVector vRight = vUp.Cross( vVel );

		if( vRight.Dot( vNewVel ) < 0.f )
		{
			vNewVel = -vRight;
		}
		else {
			vNewVel = vRight;
		}
	}

	// Keep magnitude of velocity constant.

	vNewVel.Normalize();
	vNewVel *= fMag;

	// Calculate new position.
	// Bail if new position is out of volumes.
	// Bail if new position is in wrong volume.

	LTVector vNewPos = vMyPos + vNewVel;
	if( !m_pDestVolume->Inside2d( vNewPos, m_pAI->GetRadius() ) )
	{
		return;
	}


	// Move toward new position.

	*pvNewPos = vNewPos;

	if( eMovementType == kAM_Encode_GB )
	{
		m_pAI->FacePosMoving( m_pAI->GetPosition() );
	}
	else {
		m_pAI->FacePosMoving( vNewPos );
	}
}
Exemplo n.º 12
0
bool CAISensorBerserker::UpdateSensor()
{
	if ( !m_pAI )
	{
		return false;
	}

	// Fail if AI was not previously aware of a character target.

	if( !(m_pAI->GetAIBlackBoard()->GetBBTargetedTypeMask() & kTarget_Character) )
	{
		return false;
	}

	// Fail if the AI already has a berserker target

	if ( m_pAI->HasTarget( kTarget_Berserker ) )
	{
		return false;
	}

	float flMin = 0.f;
	float flMax = 0.f;
	GetBerserkerSenseRange( &flMin, &flMax );
	float flMinSqr = flMin*flMin;
	float flMaxSqr = flMax*flMax;

	//
	// Remove the any current berserker facts if the AI is out of range.
	//

	AllBerserkerFacts all;
	m_pAI->GetAIWorkingMemory()->CollectFact( all );
	for ( int iFact = 0; iFact < all.GetCount(); ++iFact )
	{
		CAIWMFact* pFact = all.GetFact( iFact );
		if ( pFact )
		{
			LTVector vTargetPos;
			g_pLTServer->GetObjectPos( pFact->GetTargetObject(), &vTargetPos );
			float flDistSqr = vTargetPos.DistSqr( m_pAI->GetPosition());
			if ( flDistSqr > flMaxSqr || flDistSqr < flMinSqr)
			{
				m_pAI->GetAIWorkingMemory()->ClearWMFact( pFact );
			}
		}
	}

	//
	// Find a valid berserker target.
	//

	// Fail if there no target to perform a berserk attack against.

	BerserkerTargetCollector Berserker( m_pAI, flMinSqr, flMaxSqr );
	m_pAI->GetAIWorkingMemory()->CollectFact( Berserker );

	if ( !Berserker.m_pBestTargetFact )
	{
		return false;
	}

	// Add a desire to perform a berserk attack against if this target if one
	// doesn't already exist.

	CAIWMFact factQuery;
	factQuery.SetFactType( kFact_Desire );
	factQuery.SetDesireType( kDesire_Berserker );
	factQuery.SetTargetObject( Berserker.m_pBestTargetFact->GetTargetObject() );
	CAIWMFact* pBerserkerDesire = m_pAI->GetAIWorkingMemory()->FindWMFact( factQuery );
	if ( !pBerserkerDesire )
	{
		CAIWMFact* pBerserkerDesire = m_pAI->GetAIWorkingMemory()->CreateWMFact( kFact_Desire );
		pBerserkerDesire->SetDesireType( kDesire_Berserker );
		pBerserkerDesire->SetTargetObject( Berserker.m_pBestTargetFact->GetTargetObject() );
		pBerserkerDesire->SetTime( g_pLTServer->GetTime() );
	}

	// Flag a target re-evaluation, but only if the AI is unarmed

	if ( !AIWeaponUtils::HasWeaponType( m_pAI, kAIWeaponType_Ranged, AIWEAP_CHECK_HOLSTER ) 
		&& !AIWeaponUtils::HasWeaponType( m_pAI, kAIWeaponType_Melee, AIWEAP_CHECK_HOLSTER ) )
	{
		m_pAI->GetAIBlackBoard()->SetBBInvalidateTarget( true );
	}

	return true;
}
Exemplo n.º 13
0
void CTriggerFX::CalcLocalClientDistance()
{
	m_fDistPercent = -1.0f;

	// Don't do anything if the trigger is locked or our distances are too small..

	if( m_cs.bLocked || (m_cs.fHUDAlwaysOnDist <= 0.0f && m_cs.fHUDLookAtDist <= 0.0f) )
		return;

	// See if the player is within the trigger...

	LTVector vTrigPos;
	g_pLTClient->GetObjectPos( m_hServerObject, &vTrigPos );
	g_pLTClient->SetObjectPos( m_hDimsObject, vTrigPos );

	HLOCALOBJ	hPlayerObj = g_pLTClient->GetClientObject();
	LTVector	vPlayerPos, vPlayerDims;

	g_pLTClient->GetObjectPos( hPlayerObj, &vPlayerPos );

	// Make sure we are within the display radius...
	
	float	fMaxRadius = LTMAX( m_cs.fHUDAlwaysOnDist, m_cs.fHUDLookAtDist );
	float	fDistSqr = vTrigPos.DistSqr( vPlayerPos );
	bool	bWithinLookAtDist = (fDistSqr < m_cs.fHUDLookAtDist * m_cs.fHUDLookAtDist);
	bool	bWithinAlwaysOnDist = (fDistSqr < m_cs.fHUDAlwaysOnDist * m_cs.fHUDAlwaysOnDist);

	if( !bWithinLookAtDist && !bWithinAlwaysOnDist )
	{
		// We are not close enough...
		
		m_bWithinIndicatorRadius = false;
		return;
	}

	m_bWithinIndicatorRadius = true;

	g_pPhysicsLT->GetObjectDims( hPlayerObj, &vPlayerDims );

	LTVector vTrigMin = vTrigPos - m_cs.vDims;
	LTVector vTrigMax = vTrigPos + m_cs.vDims;
	LTVector vPlayerMin = vPlayerPos - vPlayerDims;
	LTVector vPlayerMax = vPlayerPos + vPlayerDims;

	// Check if we are within the height of the trigger...

	bool bWithinHeight =false;
	if( vPlayerMax.y > vTrigMin.y && vPlayerMin.y < vTrigMax.y )
		bWithinHeight = true;
	
	// See if we are inside the trigger at all...

	if( bWithinHeight && (BoxesIntersect( vTrigMin, vTrigMax, vPlayerMin, vPlayerMax ) || bWithinAlwaysOnDist))
	{
		m_fDistPercent = 1.0f;
	}
	else
	{
		// We are within the height of the trigger, show how far from it we are...

		float fMinDist = (vPlayerDims.x + vPlayerDims.z) * 0.5f;
		float fMaxDist = 100000.0f;

		LTVector vDir;

		if( bWithinAlwaysOnDist )
		{
			vDir = vTrigPos - vPlayerPos;
			vDir.Normalize();
		}
		else
		{
			LTRotation const& rRot = g_pPlayerMgr->GetPlayerCamera()->GetCameraRotation( );
			vDir = rRot.Forward();
		}

		IntersectQuery IQuery;
		IntersectInfo IInfo;

		IQuery.m_From		= vPlayerPos + (vDir * fMinDist);
		IQuery.m_To			= IQuery.m_From + (vDir * fMaxDist);
		IQuery.m_Flags		= INTERSECT_OBJECTS | INTERSECT_HPOLY | IGNORE_NONSOLID;
				
		// We need to recieve rayhits for this intersect call...

		g_pCommonLT->SetObjectFlags( m_hDimsObject, OFT_Flags, FLAG_RAYHIT, FLAG_RAYHIT );

		if( g_pLTClient->IntersectSegment( IQuery, &IInfo ))
		{
			if( IInfo.m_hObject == m_hDimsObject )
			{
				IInfo.m_Point.y = vPlayerPos.y;
				float fDist = vPlayerPos.Dist( IInfo.m_Point );
				m_fDistPercent = 1.0f - (fDist / fMaxRadius);
			}
		}

		// No more rayhits...
		
		g_pCommonLT->SetObjectFlags( m_hDimsObject, OFT_Flags, 0, FLAG_RAYHIT );
	}
}
Exemplo n.º 14
0
bool CAISensorPassTarget::NeedToHoldPosition( bool* pbCalledFindPath ) 
{
	// Sanity check.

	if( !pbCalledFindPath )
	{
		return false;	
	}

	// No need to hold position if not targeting a character.

	if( !m_pAI->HasTarget( kTarget_Character ) )
	{
		m_hVerifiedNode = NULL;
		return false;
	}

	// Only check for passing the target if we are within some distance of the target.

	LTVector vTargetPos = m_pAI->GetAIBlackBoard()->GetBBTargetPosition();
	float fDistSqr = vTargetPos.DistSqr( m_pAI->GetPosition() );
	if( fDistSqr > g_pAIDB->GetAIConstantsRecord()->fHoldPositionDistanceSqr )
	{
		m_hVerifiedNode = NULL;
		return false;	
	}

	// Character is outside of the NavMesh.

	ENUM_NMPolyID ePolyTarget = GetTargetNavMeshPoly();
	if( ePolyTarget == kNMPoly_Invalid )
	{
		m_hVerifiedNode = NULL;
		return false;
	}

	// Bail if AI is not going for cover or ambush.

	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 ) ) )
	{
		m_hVerifiedNode = NULL;
		return false;
	}

	// Bail if AI is scripted to go for cover.

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

	// We have already determined that we can get to this node without
	// crossing the target's position.

	HOBJECT hNode = pFact->GetTargetObject();
	if( hNode == m_hVerifiedNode )
	{
		// AI is not going anywhere.

		CAIPathNavMesh* pNMPath = m_pAI->GetAINavigationMgr()->GetNMPath();
		if( ( !pNMPath ) ||
			( !m_pAI->GetAINavigationMgr()->IsNavSet() ) ||
			( m_pAI->GetAIBlackBoard()->GetBBDestStatus() != kNav_Set ) )
		{
			return false;
		}

		// Existing path is still valid.  Path does not cross target.

		if( !PathIncludesPoly( *pNMPath, ePolyTarget ) )
		{
			return false;
		}
	}

	// No path exists to node.

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

	// Path does cross target's position.

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

	// Path does not cross target's position.

	m_hVerifiedNode = hNode;
	return false; 
}