void CAIGoalGuard::UpdateGoal() { CAIState* pState = m_pAI->GetState(); switch(pState->GetStateType()) { // If state is idle, and a guard node is set, set state to goto. case kState_HumanIdle: HandleStateIdle(); break; case kState_HumanGoto: HandleStateGoto(); break; // State should only be idle or goto. default: AIASSERT(0, m_pAI->m_hObject, "CAIGoalGuard::UpdateGoal: Unexpected State."); } }
bool CAIActionGotoValidPosition::IsActionComplete( CAI* pAI ) { // Goto is complete if state is complete. if( !pAI->GetState() ) { AIASSERT(0, pAI->GetHOBJECT(), "CAIActionGotoValidPosition::IsActionComplete : AI has no state."); return false; } // Goto is complete. if ( pAI->GetState()->GetStateStatus() == kAIStateStatus_Complete ) { return true; } return false; }
void CAIGoalAbstractUseObject::HandleStateDraw() { switch( m_pAI->GetState()->GetStateStatus() ) { case kSStat_Initialized: break; case kSStat_FailedComplete: CompleteUseObject(); break; case kSStat_StateComplete: CompleteUseObject(); break; // Unexpected StateStatus. default: AIASSERT(0, m_pAI->m_hObject, "CAIGoalAbstractUseObject::HandleStateDraw: Unexpected State Status."); } }
void CAIActionAbstract::SolvePlanWSVariable( CAI* pAI, CAIWorldState& wsWorldStateCur, CAIWorldState& wsWorldStateGoal ) { SAIWORLDSTATE_PROP* pEffect; SAIWORLDSTATE_PROP* pProp; // Iterate over all effects. for( unsigned int iEffect=0; iEffect < kWSK_Count; ++iEffect ) { // Get a pointer to the indexed effect. pEffect = m_wsWorldStateEffects.GetWSProp( iEffect ); if( !pEffect ) { continue; } // The effect is not a variable. // Get the value of the property effected. if( pEffect->eWSType != kWST_Variable ) { pProp = wsWorldStateGoal.GetWSProp( pEffect->eWSKey, pAI->m_hObject ); } // The effect is a variable. // Get the value of the property referenced by the variable effected. else { pProp = wsWorldStateGoal.GetWSProp( pEffect->eVariableWSKey, pAI->m_hObject ); } // Set the current world state's property to match the goal. if( pProp ) { // Note that we may set the prop to a different key, as specified by a variable. AIASSERT( pProp->eWSType != kWST_Variable, pAI->m_hObject, "CAIActionAbstract::SolvePlanWSVariable: Setting a world prop to another variable!" ); wsWorldStateCur.SetWSProp( pEffect->eWSKey, pProp ); } } }
void CAIGoalAbstractUseObject::HandleStateHolster() { switch( m_pAI->GetState()->GetStateStatus() ) { case kSStat_Initialized: break; case kSStat_FailedComplete: AIASSERT( 0, m_pAI->m_hObject, "CAIGoalAbstractUseObject::HandleStateHolster: Failed to holster weapon." ); m_fCurImportance = 0.f; break; case kSStat_StateComplete: SetStateUseObject(); break; // Unexpected StateStatus. default: ASSERT(!"CAIGoalAbstractUseObject::HandleStateHolster: Unexpected State Status."); } }
void CAIGoalAbstractSearch::HandleStateDraw() { switch( m_pAI->GetState()->GetStateStatus() ) { case kSStat_Initialized: break; case kSStat_FailedComplete: m_pGoalMgr->UnlockGoal( this ); m_fCurImportance = 0.f; break; case kSStat_StateComplete: SetStateSearch(); break; // Unexpected StateStatus. default: AIASSERT(0, m_pAI->m_hObject, "CAIGoalAbstractSearch::HandleStateDraw: Unexpected State Status."); } }
LTBOOL CAIPathKnowledgeMgr::RegisterPathKnowledge(AIVolume *pDestVolume, CAIPathMgr::EnumPathBuildStatus eStatus) { // Existing path knowledge is only valid while our index matches // the global index. if( m_nPathKnowledgeIndex != g_pAIPathMgr->GetPathKnowledgeIndex() ) { ClearPathKnowledge(); m_nPathKnowledgeIndex = g_pAIPathMgr->GetPathKnowledgeIndex(); } // Search for existing knowledge of paths to the dest volume. AIPATH_KNOWLEDGE_MAP::iterator it = m_mapPathKnowledge.find( pDestVolume ); // Register a new piece of path knowledge. if( it == m_mapPathKnowledge.end() ) { if( eStatus == CAIPathMgr::kPath_NoPathFound ) { AITRACE( AIShowPaths, ( m_pAI->m_hObject, "Registering NoPathFound for %s", pDestVolume->GetName() ) ); } m_mapPathKnowledge.insert( AIPATH_KNOWLEDGE_MAP::value_type( pDestVolume, eStatus ) ); return LTTRUE; } // There is a problem if the status has changed! // The status of a dest volume should only change if something has happened to // the connectivity: e.g. a door was locked/unlocked, a volume was enabled/disabled, // an AI used a volume flagged as OnlyJumpDown, etc. // In these cases, Path Knowledge should be cleared. if( it->second != eStatus ) { AIASSERT( 0, m_pAI->m_hObject, "CAIPathKnowledgeMgr::RegisterPathKnowledge: Volume status has changed!" ); return LTFALSE; } return LTTRUE; }
//---------------------------------------------------------------------------- // // ROUTINE: CAIGoalResurrecting::HandleStateResurrecting() // // PURPOSE: // //---------------------------------------------------------------------------- void CAIGoalResurrecting::HandleStateResurrecting() { switch( m_pAI->GetState()->GetStateStatus() ) { case kSStat_Initialized: break; case kSStat_Resurrecting: break; case kSStat_RegainingConsciousness: break; case kSStat_Conscious: { // Reset AIs default senses, from aibutes.txt. m_pAI->ResetBaseSenseFlags(); m_pGoalMgr->UnlockGoal(this); if ( m_pAI->CanSearch() ) { // Search. SetStateSearch(); } else { // Go aware. m_pAI->SetState( kState_HumanAware ); } // Set the importance to something fairly low, so that // anything else will be preferable. SetCurImportance( 8 ); } break; // Unexpected StateStatus. default: AIASSERT(0, m_pAI->m_hObject, "CAIGoalUnconscious::HandleStateUnconscious: Unexpected State Status."); } }
// ----------------------------------------------------------------------- // // // ROUTINE: CAIUtils::FindTrueCeilingHeight // // PURPOSE: Find height of the ceiling above an AI at some position. // // ----------------------------------------------------------------------- // LTBOOL CAIUtils::FindTrueCeilingHeight(float flCheckDist, const LTVector& vDims, const LTVector& vPos, LTFLOAT* pfFloorHeight) { AIASSERT( pfFloorHeight, m_hObject, "CAIHuman::FindFloorHeight: fFloorHeight is NULL" ); IntersectQuery IQuery; IntersectInfo IInfo; IQuery.m_From = LTVector(vPos.x, vPos.y - vDims.y, vPos.z); IQuery.m_To = LTVector(vPos.x, vPos.y + flCheckDist, vPos.z); IQuery.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID; IQuery.m_FilterFn = GroundFilterFn; g_cIntersectSegmentCalls++; if (g_pLTServer->IntersectSegment(&IQuery, &IInfo) && (IsMainWorld(IInfo.m_hObject) || (OT_WORLDMODEL == GetObjectType(IInfo.m_hObject)))) { *pfFloorHeight = IInfo.m_Point.y; return LTTRUE; } return LTFALSE; }
void CAIGoalAttackProp::HandleStateAttackProp() { switch( m_pAI->GetState()->GetStateStatus() ) { case kSStat_Initialized: break; case kSStat_StateComplete: { // Disable node when prop has been destroyed. AINode* pNode = (AINode*)g_pLTServer->HandleToObject(m_hNode); pNode->Disable(); m_hNode = LTNULL; m_fCurImportance = 0.f; } break; // Unexpected StateStatus. default: AIASSERT(0, m_pAI->m_hObject, "CAIGoalAttackProp::HandleStateAttackProp: Unexpected State Status."); } }
CAIGoalWork::~CAIGoalWork() { // If destructing because the AI died, // and no special death was played, // and node is only locked by this goal, // then turn off the object. if( m_pAI->IsDead() && m_hNodeUseObject && m_bLockedNode && !m_bPlayedSpecialDeathAnim ) { AINodeUseObject* pNodeUseObject = (AINodeUseObject*)g_pLTServer->HandleToObject(m_hNodeUseObject); AIASSERT( pNodeUseObject && pNodeUseObject->IsLocked(), m_pAI->m_hObject, "CAIGoalAbstractUseObject::DeactivateGoal: Node is NULL or not locked" ); if( pNodeUseObject && pNodeUseObject->GetHObject() && ( pNodeUseObject->GetLockCount() == 1 ) ) { SendTriggerMsgToObject( m_pAI, pNodeUseObject->GetHObject(), LTFALSE, "OFF" ); } } }
void CAIGoalRespondToBackup::HandleStateGoto() { switch( m_pAI->GetState()->GetStateStatus() ) { case kSStat_Initialized: break; case kSStat_StateComplete: if(m_pAI->CanSearch()) { SetStateSearch(); } else { m_pGoalMgr->UnlockGoal(this); m_pAI->SetState( kState_HumanAware ); } break; // Unexpected StateStatus. default: AIASSERT(0, m_pAI->m_hObject, "CAIGoalGetBackup::HandleStateGoto: Unexpected State Status."); } }
void CAIGoalPatrol::HandleStatePatrol() { switch( m_pAI->GetState()->GetStateStatus() ) { case kSStat_Initialized: { // Keep track of the current patrol node, in case we get interrupted. AINodePatrol* pPatrolNode = ((CAIHumanStatePatrol*)(m_pAI->GetState()))->GetNode(); if( pPatrolNode && ( pPatrolNode->m_hObject != m_hPatrolNode ) ) { m_hPatrolNode = pPatrolNode->m_hObject; // If AI holstered his weapon from code (denoted with ~) // unholster it when he reaches his first patrol node. if( ( !m_pAI->GetPrimaryWeapon() ) && ( m_pAI->HasHolsterString() ) && ( m_pAI->GetHolsterString()[0] == '~' ) ) { m_pAI->SetState( kState_HumanDraw ); m_pAI->GetState()->PlayFirstSound( LTFALSE ); } } } break; case kSStat_StateComplete: case kSStat_FailedComplete: case kSStat_FailedSetPath: m_pAI->SetState( kState_HumanIdle ); break; // Unexpected StateStatus. default: AIASSERT(0, m_pAI->m_hObject, "CAIGoalPatrol::HandleStatePatrol: Unexpected State Status."); } }
CAICentralKnowledgeRecord::CAICentralKnowledgeRecord() { if( g_pAICentralKnowledgeMgr ) { m_hAI.SetReceiver( *g_pAICentralKnowledgeMgr ); m_hKnowledgeTarget.SetReceiver( *g_pAICentralKnowledgeMgr ); } else { AIASSERT( 0, NULL, "No g_pAICentralKnowledgeMgr." ); } m_eKnowledgeType = kCK_InvalidType; m_hAI = LTNULL; m_pAI = LTNULL; m_hKnowledgeTarget = LTNULL; m_pKnowledgeTarget = LTNULL; m_bLinkKnowledge = LTTRUE; m_fKnowledgeData = 0.f; m_bKnowledgeDataIsTime = LTFALSE; }
void CAIGoalAbstractUseObject::DeactivateGoal() { super::DeactivateGoal(); // Unlock the node after the entire duration of the goal. // This includes time spent holstering and drawing weapons. AINodeUseObject* pNodeUseObject = (AINodeUseObject*)g_pLTServer->HandleToObject(m_hNodeUseObject); AIASSERT( pNodeUseObject && pNodeUseObject->IsLocked(), m_pAI->m_hObject, "CAIGoalAbstractUseObject::DeactivateGoal: Node is NULL or not locked" ); if( m_bLockedNode && pNodeUseObject ) { pNodeUseObject->Unlock( m_pAI->m_hObject ); m_bLockedNode = LTFALSE; } // If we get drawn away to do something else, forget about // the node, so that we will search again from where ever we // end up. // Do not set m_hLastNodeUseObject, because we may not // have finished using the object. ClearUseObjectNode(); }
void CAIGoalPatrol::UpdateGoal() { CAIState* pState = m_pAI->GetState(); switch(pState->GetStateType()) { // If state is idle, and a patrol node is set, set state to patrol. case kState_HumanIdle: HandleStateIdle(); break; case kState_HumanPatrol: HandleStatePatrol(); break; case kState_HumanDraw: HandleStateDraw(); break; // State should only be idle or patrol. default: AIASSERT(0, m_pAI->m_hObject, "CAIGoalPatrol::UpdateGoal: Unexpected State."); } }
void CAIGoalAttackRangedDynamic::HandleStateAttackMove() { switch( m_pAI->GetState()->GetStateStatus() ) { case kSStat_Initialized: break; case kSStat_FailedComplete: m_pGoalMgr->UnlockGoal( this ); ResetMoveTime(); SetStateAttack(); break; case kSStat_StateComplete: m_pGoalMgr->UnlockGoal( this ); ResetMoveTime(); SetStateAttack(); break; // Unexpected StateStatus. default: AIASSERT(0, m_pAI->m_hObject, "CAIGoalAttackRangedDynamic::HandleStateAttackMove: Unexpected State Status."); } }
LTBOOL CAIGoalGuard::HandleNameValuePair(const char *szName, const char *szValue) { AIASSERT(szName && szValue, m_pAI->m_hObject, "CAIGoalGuard::HandleNameValuePair: Name or value is NULL."); if( super::HandleNameValuePair(szName, szValue) ) { return LTTRUE; } if ( !_stricmp(szName, "NODE") ) { // If Goal was already active (walking to previous guard node) // Reset the goal. if( m_pGoalMgr->IsCurGoal( this ) ) { m_pAI->SetState( kState_HumanIdle ); } AINode* pNode = g_pAINodeMgr->GetNode(szValue); if( pNode ) { SetGuardNode( pNode ); RecalcImportance(); AITRACE( AIShowGoals, ( m_pAI->m_hObject, "CAIGoal%s: NODE=%s", s_aszGoalTypes[GetGoalType()], ::ToString( pNode->GetName() ) ) ); } else { AIError( "%s Cannot find node! CAIGoal%s: NODE=%s", m_pAI->GetName(), s_aszGoalTypes[GetGoalType()], szValue ); } return LTTRUE; } return LTFALSE; }
LTBOOL CAIHumanStateAttackMove::Init(CAIHuman* pAIHuman) { if ( !super::Init(pAIHuman) ) { return LTFALSE; } if ( !m_pStrategyShoot->Init(pAIHuman) ) { return LTFALSE; } if ( !m_pStrategyFollowPath->Init(pAIHuman, m_pStrategyShoot) ) { return LTFALSE; } m_pStrategyFollowPath->SetMedium(CAIHumanStrategyFollowPath::eMediumGround); // Keep track of how many AI are attacking the same target. if( m_pAIHuman->HasTarget() ) { if( g_pAICentralKnowledgeMgr->CountMatches( kCK_Attacking, m_pAIHuman, g_pLTServer->HandleToObject(m_pAIHuman->GetTarget()->GetObject()) ) ) { AIASSERT( 0, m_pAIHuman->m_hObject, "CAIHumanStateAttackMove::Init: Already registered attacking count!" ); } else { g_pAICentralKnowledgeMgr->RegisterKnowledge( kCK_Attacking, m_pAIHuman, g_pLTServer->HandleToObject(m_pAIHuman->GetTarget()->GetObject()), LTTRUE); } } m_pAIHuman->SetAwareness( kAware_Alert ); return LTTRUE; }
void CAIGoalFollowFootprint::ActivateGoal() { super::ActivateGoal(); AIASSERT(m_hStimulusSource != LTNULL, m_pAI->m_hObject, "CAIGoalFollowFootprint::ActivateGoal: No stimulus."); if(m_pAI->GetState()->GetStateType() != kState_HumanFollowFootprint) { m_pAI->SetState( kState_HumanFollowFootprint ); } // Reset AIs default senses, from aibutes.txt. // This is necessary because SetStateSearch may have turned some off // before this goal was reactivated. m_pAI->ResetBaseSenseFlags(); // Record the latest footstep seen. CAIHumanStateFollowFootprint* pState = (CAIHumanStateFollowFootprint*)m_pAI->GetState(); pState->ResetFootprint(m_fStimulationTime, m_vStimulusPos); pState->SetSearch(m_bSearch); m_pGoalMgr->LockGoal(this); }
CAIPlanner::~CAIPlanner() { AIASSERT( g_pAIPlanner, NULL, "CAIPlanner: No singleton." ); g_pAIPlanner = NULL; }
void CAIWeaponMelee::Fire(CAI* pAI) { if( !m_pWeapon ) { AIASSERT( 0, pAI->GetHOBJECT(), "CAIWeaponMelee::Fire: No weapon!" ); return; } if( m_eFiringState != kAIFiringState_Firing ) { return; } // Fire! LTVector vTargetPos; bool bHit = GetShootPosition( pAI, m_Context, vTargetPos ); if (DefaultFire(pAI, vTargetPos, m_pAIWeaponRecord->bAIAnimatesReload)) { // Decrement burst count for this shot. m_nBurstShots--; } // Knock the player back, if the hit inflicted damage. if( bHit ) { CPlayerObj* pPlayer = NULL; HOBJECT hTarget = pAI->GetAIBlackBoard()->GetBBTargetObject(); if( IsPlayer( hTarget ) ) { pPlayer = (CPlayerObj*)g_pLTServer->HandleToObject( hTarget ); } if( pPlayer && ( m_pAIWeaponRecord->fPlayerPusherRadius > 0.f ) && ( m_pAIWeaponRecord->fPlayerPusherForce > 0.f ) && ( pPlayer->GetDestructible() ) && ( pPlayer->GetDestructible()->GetLastDamageTime() == g_pLTServer->GetTime() ) && ( pPlayer->GetDestructible()->GetLastDamager() == pAI->m_hObject ) ) { if( ( pPlayer->GetDestructible()->GetLastArmorAbsorb() > 0.f ) || ( pPlayer->GetDestructible()->GetLastDamage() > 0.f ) ) { pPlayer->PushCharacter( pAI->GetPosition(), m_pAIWeaponRecord->fPlayerPusherRadius, 0.f, 0.3f, m_pAIWeaponRecord->fPlayerPusherForce ); } } // Only play if we've been targeting someone for at least 5 seconds. // This ensures we first play higher priority reaction sounds. if( IsCharacter( hTarget ) ) { CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject( hTarget ); if( pChar && ( pChar->GetDestructible() ) && ( pChar->GetDestructible()->GetLastDamageTime() == g_pLTServer->GetTime() ) && ( pChar->GetDestructible()->GetLastDamager() == pAI->m_hObject ) && ( pAI->GetAIBlackBoard()->GetBBTargetChangeTime() < g_pLTServer->GetTime() - 5.f ) ) { HOBJECT hAlly = g_pAICoordinator->FindAlly( pAI->m_hObject, hTarget ); if( hAlly ) { g_pAISoundMgr->RequestAISound( hAlly, kAIS_HitSeenMelee, kAISndCat_Event, hTarget, 0.5f ); } } } } }
void CAIHumanStateAttackMove::Update() { super::Update(); // Make sure we have a target if ( !GetAI()->HasTarget() ) { m_eStateStatus = kSStat_FailedComplete; return; } HOBJECT hTarget = GetAI()->GetTarget()->GetObject(); HOBJECT hAI = GetAI()->m_hObject; // Head and Torso tracking. if( m_bFirstUpdate ) { GetAI()->SetNodeTrackingTarget( kTrack_AimAt, hTarget, "Head" ); } // Handle update appropriately for the type of move. switch( m_eAttackMove ) { // Step. case kAP_ShuffleRight: case kAP_ShuffleLeft: if( m_bFirstUpdate ) { // Snap AI to face the direction of his torso. GetAI()->FaceDir( GetAI()->GetTorsoForward() ); GetAI()->FaceTargetRotImmediately(); GetAnimationContext()->ClearLock(); } else if( !GetAnimationContext()->IsLocked() ) { m_eStateStatus = kSStat_StateComplete; } // Head and Torso tracking. GetAI()->EnableNodeTracking( kTrack_AimAt, hTarget ); break; // BackUp. case kAP_BackUp: case kAP_FlankLeft: case kAP_FlankRight: if( m_pStrategyFollowPath->IsUnset() ) { if( m_eAttackMove == kAP_BackUp ) { m_pStrategyFollowPath->SetMovement( kAP_BackUp ); } else { m_pStrategyFollowPath->SetMovement( kAP_Run ); } m_bTurnedAround = LTFALSE; if( !m_pStrategyFollowPath->Set( m_vAttackMoveDest, LTFALSE ) ) { m_eStateStatus = kSStat_FailedComplete; } } if( m_pStrategyFollowPath->IsDone() ) { m_eStateStatus = kSStat_StateComplete; } else if( m_pStrategyFollowPath->IsSet() ) { SelectMoveAnim(); m_pStrategyFollowPath->Update(); } if( m_pStrategyShoot->ShouldReload() ) { m_pStrategyShoot->Reload(LTTRUE); } if( m_pStrategyShoot->IsReloading() || m_pStrategyShoot->IsFiring() || GetAI()->GetTarget()->IsVisibleCompletely() ) { m_pStrategyShoot->Update(); } // Head and Torso tracking. GetAI()->EnableNodeTracking( kTrack_AimAt, LTNULL ); break; default: AIASSERT( 0, GetAI()->m_hObject, "CAIHumanStateAttackMove::Update: Unexpected attack move." ); m_eStateStatus = kSStat_FailedComplete; break; } }
void AINavMeshLinkAbstract::ReadProp(const GenericPropList *pProps) { const char* pszPropString = pProps->GetString( "Name", "" ); if( pszPropString[0] ) { m_strName = pszPropString; } // Read the NavMeshLinkID assigned to this link. float f = pProps->GetReal( "AINavMeshLinkID", (float)m_eNMLinkID ); m_eNMLinkID = ( ENUM_NMLinkID )( int )f; // Read SmartObject type. AIDB_SmartObjectRecord* pSmartObject = NULL; pszPropString = pProps->GetString( "SmartObject", "" ); if( pszPropString[0] ) { m_nSmartObjectID = g_pAIDB->GetAISmartObjectRecordID( pszPropString ); AIASSERT( m_nSmartObjectID != kAISmartObjectID_Invalid, m_hObject, "AINavMeshLinkAbstract::ReadProp: SmartObject is NULL."); } // Read EnabledAwarenessMod pszPropString = pProps->GetString( "RequiredAwarenessMod", "" ); if( pszPropString[0] ) { m_eEnabledAwarenessMod = StringToAwarenessMod( pszPropString ); } // Read MinEnabledAwareness. pszPropString = pProps->GetString( "MinEnabledAwareness", "Relaxed" ); if( pszPropString[0] ) { m_eMinEnabledAwareness = StringToAwareness( pszPropString ); } // Read MaxEnabledAwareness. pszPropString = pProps->GetString( "MaxEnabledAwareness", "Alert" ); if( pszPropString[0] ) { m_eMaxEnabledAwareness = StringToAwareness( pszPropString ); } // Read MinActiveAwareness. pszPropString = pProps->GetString( "MinActiveAwareness", "Relaxed" ); if( pszPropString[0] ) { m_eMinActiveAwareness = StringToAwareness( pszPropString ); } // Read MaxActiveAwareness. pszPropString = pProps->GetString( "MaxActiveAwareness", "Alert" ); if( pszPropString[0] ) { m_eMaxActiveAwareness = StringToAwareness( pszPropString ); } // Read Active flag. m_bLinkActive = pProps->GetBool( "Active", m_bLinkActive ); // Read StartDisabled flag. m_bLinkEnabled = !pProps->GetBool( "StartDisabled", !m_bLinkEnabled ); }
uint32 CAICentralKnowledgeMgr::CountMatches(EnumAICentralKnowledgeType eKnowledgeType) { AIASSERT( eKnowledgeType != kCK_InvalidType, LTNULL, "CountTargetMatches::CountMatchingKnowledge: Query needs a valid type." ); return (uint32)(m_mapCentralKnowledge.count( eKnowledgeType )); }
LTBOOL CAIGoalAttackRangedDynamic::SelectAttackMove() { uint32 dwExcludeVolumes = AIVolume::kVolumeType_Ladder | AIVolume::kVolumeType_Stairs | AIVolume::kVolumeType_JumpOver | AIVolume::kVolumeType_JumpUp | AIVolume::kVolumeType_AmbientLife | AIVolume::kVolumeType_Teleport; LTVector vPos = m_pAI->GetPosition(); // Randomly select an attack move. uint32 iMove = GetRandom( 0, kNumAttackMoves - 1 ); uint32 iFirstTry = iMove; EnumAnimProp eMove = kAP_None; LTVector vDest( 0.f, 0.f, 0.f); LTBOOL bTriedBackup = LTFALSE; // Search for a valid move, starting from a random index. while( 1 ) { // Check if move is valid. switch( m_eAttackMoves[iMove] ) { // Step right. case kAP_ShuffleRight: vDest = vPos + ( m_pAI->GetTorsoRight() * ( m_pAI->GetBrain()->GetDodgeVectorShuffleDist() + m_pAI->GetRadius() ) ); eMove = kAP_ShuffleRight; break; // Step left. case kAP_ShuffleLeft: vDest = vPos - ( m_pAI->GetTorsoRight() * ( m_pAI->GetBrain()->GetDodgeVectorShuffleDist() + m_pAI->GetRadius() ) ); eMove = kAP_ShuffleLeft; break; // BackUp. case kAP_BackUp: if( m_pAI->GetBrain()->AttacksWhileMoving() ) { vDest = vPos - ( m_pAI->GetTorsoForward() * ( m_pAI->GetBrain()->GetAIData( kAIData_DynMoveBackupDist ) + m_pAI->GetRadius() ) ); eMove = kAP_BackUp; } break; // Flank left. case kAP_FlankLeft: if( m_pAI->GetBrain()->AttacksWhileMoving() ) { vDest = m_pAI->GetTarget()->GetVisiblePosition() - ( m_pAI->GetTorsoRight() * m_pAI->GetBrain()->GetAIData( kAIData_DynMoveFlankWidthDist ) ); vDest += m_pAI->GetTorsoForward() * m_pAI->GetBrain()->GetAIData( kAIData_DynMoveFlankPassDist ); eMove = kAP_FlankLeft; } break; // Flank right. case kAP_FlankRight: if( m_pAI->GetBrain()->AttacksWhileMoving() ) { vDest = m_pAI->GetTarget()->GetVisiblePosition() + ( m_pAI->GetTorsoRight() * m_pAI->GetBrain()->GetAIData( kAIData_DynMoveFlankWidthDist ) ); vDest += m_pAI->GetTorsoForward() * m_pAI->GetBrain()->GetAIData( kAIData_DynMoveFlankPassDist ); eMove = kAP_FlankRight; } break; // Unexpected. default: AIASSERT( 0, m_pAI->m_hObject, "CAIGoalAttackRangedDynamic::SelectAttackMove: Unexpected attack move." ); return LTFALSE; } // Do an attack move if the destination is in range, and there is a clear path. if( ( eMove != kAP_None ) && ( ( eMove != kAP_BackUp ) || ( !bTriedBackup ) ) && ( g_pAIVolumeMgr->StraightPathExists( m_pAI, vPos, vDest, m_pAI->GetVerticalThreshold(), dwExcludeVolumes, m_pAI->GetLastVolume() ) ) && ( !g_pCharacterMgr->RayIntersectAI( vPos, vDest, m_pAI, LTNULL, LTNULL ) ) ) { m_pAI->SetState( kState_HumanAttackMove ); CAIHumanStateAttackMove* pAttackMoveState = (CAIHumanStateAttackMove*)m_pAI->GetState(); pAttackMoveState->SetAttackMove( eMove ); pAttackMoveState->SetAttackMoveDest( vDest ); m_pGoalMgr->LockGoal( this ); return LTTRUE; } if( eMove == kAP_BackUp ) { bTriedBackup = LTTRUE; } // Try another move. iMove = ( iMove + 1 ) % kNumAttackMoves; eMove = kAP_None; // All moves were tested, and no move was found. if( iMove == iFirstTry ) { return LTFALSE; } } // Should never get here. AIASSERT( 0, m_pAI->m_hObject, "CAIGoalAttackRangedDynamic::SelectAttackMove: Should never get here." ); return LTFALSE; }
CAIClassFactory::CAIClassFactory() { // Create singleton. AIASSERT(g_pAIClassFactory == NULL, LTNULL, "CAIClassFactory: Class factory already exists."); g_pAIClassFactory = this; }
//---------------------------------------------------------------------------- // // ROUTINE: CRelationMgr::AddObjectRelationMgrInstance() // // PURPOSE: Adds a new ObjectRelationMgr instance to the list of instances. // //---------------------------------------------------------------------------- void CRelationMgr::AddObjectRelationMgr(CObjectRelationMgr* pObjectRelationMgr, HOBJECT hObject ) { AIASSERT( !IsObjectRelationMgrLinked(pObjectRelationMgr), hObject, "AddCollective: Attempted duplicate addition of collective" ); m_listpObjectRelationMgrs.push_back( const_cast<CObjectRelationMgr*>(pObjectRelationMgr) ); LinkObjectRelationMgr( pObjectRelationMgr, hObject ); }
bool CCharacterHitBox::Init(HOBJECT hModel, IHitBoxUser* pUser) { AIASSERT( pUser, m_hObject, "CharacterHitBox Inited with non existant IHitBoxUser" ); AIASSERT( hModel, m_hObject, "CharacterHitBox Inited with non existant hObject" ); AIASSERT( m_hObject, m_hObject, "CharacterHitBox does not exist" ); AIASSERT( pUser, m_hObject, "" ); AIASSERT( dynamic_cast<IHitBoxUser*>(g_pLTServer->HandleToObject(hModel)) == pUser, hModel, "Passed in hModel and pUser should reference the same class -- HandleToObject(hModel) should return what pUser points to" ); m_hModel = hModel; m_pHitBoxUser = pUser; // Set my flags... g_pCommonLT->SetObjectFlags(m_hObject, OFT_Flags, FLAG_RAYHIT | FLAG_TOUCHABLE, FLAGMASK_ALL); g_pCommonLT->SetObjectFlags( m_hObject, OFT_User, USRFLG_HITBOX | USRFLG_CHARACTER, USRFLG_HITBOX | USRFLG_CHARACTER ); // Set our user flags to USRFLG_CHARACTER, so the client will process // us like a character (for intersect segments)... g_pCommonLT->SetObjectFlags(m_hObject, OFT_User, USRFLG_CHARACTER, USRFLG_CHARACTER); if (!g_vtShowNodeRadii.IsInitted()) { g_vtShowNodeRadii.Init(g_pLTServer, "HitBoxShowNodeRadii", NULL, 0.0f); } if (!g_vtNodeRadiusUseOverride.IsInitted()) { g_vtNodeRadiusUseOverride.Init(g_pLTServer, "HitBoxNodeRadiusOverride", NULL, 0.0f); } if (!g_vtHeadNodeRadius.IsInitted()) { g_vtHeadNodeRadius.Init(g_pLTServer, "HitBoxHeadNodeRadius", NULL, HB_DEFAULT_NODE_RADIUS); } if (!g_vtTorsoNodeRadius.IsInitted()) { g_vtTorsoNodeRadius.Init(g_pLTServer, "HitBoxTorsoNodeRadius", NULL, HB_DEFAULT_NODE_RADIUS); } if (!g_vtArmNodeRadius.IsInitted()) { g_vtArmNodeRadius.Init(g_pLTServer, "HitBoxArmNodeRadius", NULL, HB_DEFAULT_NODE_RADIUS); } if (!g_vtLegNodeRadius.IsInitted()) { g_vtLegNodeRadius.Init(g_pLTServer, "HitBoxLegNodeRadius", NULL, HB_DEFAULT_NODE_RADIUS); } if (!g_HitDebugTrack.IsInitted()) { g_HitDebugTrack.Init(g_pLTServer, "HitDebug", NULL, 0.0f); } if (!g_vtShowPlayerNodeRadii.IsInitted()) { g_vtShowPlayerNodeRadii.Init(g_pLTServer, "HitBoxShowPlayerNodeRadii", NULL, 0.0f); } SetNextUpdate(UPDATE_NEVER); return true; }
CAIPlanner::CAIPlanner() { AIASSERT( !g_pAIPlanner, NULL, "CAIPlanner: Singleton already set." ); g_pAIPlanner = this; }