LTBOOL CAISenseSeeEnemyFootprint::Update(HOBJECT hStimulus, LTFLOAT fTimeDelta) { if ( !IsCharacter(hStimulus) ) return LTFALSE; CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject(hStimulus); CTList<CharFootprintInfo*>* plistFootprints = pChar->GetFootprints(); CharFootprintInfo** ppFootprint = plistFootprints->GetItem(TLIT_FIRST); while ( ppFootprint && *ppFootprint ) { CharFootprintInfo* pFootprint = *ppFootprint; if ( m_pAI->IsPositionVisibleFromEye(CAI::DefaultFilterFn, NULL, pFootprint->vPos, (m_fDistanceSqr), LTTRUE) ) { React(); // Record the Timestamp m_fTimestamp = pFootprint->fTimeStamp; return LTTRUE; } ppFootprint = plistFootprints->GetItem(TLIT_NEXT); } return LTFALSE; }
void CCharacterMgr::CallForBackupInList(BaseAI* pInTrouble, CTList<CBaseCharacter*> & list) { if (!g_pServerDE || !pInTrouble) return; DVector vTroublePos, vHelperPos; g_pServerDE->GetObjectPos(pInTrouble->m_hObject, &vTroublePos); CBaseCharacter** pCur = DNULL; BaseAI* pAI = DNULL; pCur = list.GetItem(TLIT_FIRST); while (pCur) { pAI = (BaseAI*)*pCur; if (pAI && !pAI->IsDead()) { g_pServerDE->GetObjectPos(pAI->m_hObject, &vHelperPos); if (VEC_DIST(vTroublePos, vHelperPos) < 500.0f) { if (!pAI->m_hTarget) { pAI->SetNewTarget(pInTrouble->m_hLastDamager); pAI->TargetObject(pInTrouble->m_hLastDamager); } } } pCur = list.GetItem(TLIT_NEXT); } }
HOBJECT CCharacterMgr::CanHearEnemyFireInList(BaseAI* pTargeter, CTList<CBaseCharacter*> & list) { CBaseCharacter** pCur = DNULL; CBaseCharacter* pChar = DNULL; pCur = list.GetItem(TLIT_FIRST); HOBJECT hObj = DNULL; while (pCur) { pChar = *pCur; if (pChar && !pChar->IsDead()) { hObj = pTargeter->CanAIHearWeaponFire(pChar); if (hObj) { return hObj; } } pCur = list.GetItem(TLIT_NEXT); } return DNULL; }
void CAIMgr::UpdateAISensors() { CTList<CCharacter*>* plstChars = g_pCharacterMgr->GetCharacterList( CCharacterMgr::kList_AIs ); CCharacter** pNext; CAI* pCurAI; // No AI exist. if( plstChars->GetLength() == 0 ) { return; } // Find the next AI to update. // AI update round robin, so everyone gets the opportunity to // do a distributed update. pNext = plstChars->GetItem( TLIT_FIRST ); while( m_hNextAI && ( (*pNext)->m_hObject != m_hNextAI ) ) { pNext = plstChars->GetItem( TLIT_NEXT ); } if( !pNext ) { pNext = plstChars->GetItem( TLIT_FIRST ); } HOBJECT hFirstToUpdate = (*pNext)->m_hObject; // Iterate over all existing AI. bool bWrapped = false; bool bUpdateDistributedSensors = true; while( true ) { // Bail once we have updated everyone. if( bWrapped ) { break; } // Look ahead at the next AI to update, and flag if we've wrapped. pCurAI = (CAI*)*pNext; pNext = plstChars->GetItem( TLIT_NEXT ); if( !pNext ) { pNext = plstChars->GetItem( TLIT_FIRST ); } if( (*pNext)->m_hObject == hFirstToUpdate ) { bWrapped = true; } // Do not update sensors of dead AI. if( pCurAI->GetDestructible()->IsDead() ) { continue; } // Update all AI's sensors. // Stop updating distributed sensors once someone has performed // an expensive update. if( pCurAI->GetAISensorMgr()->UpdateSensors( bUpdateDistributedSensors ) ) { #if DISTRIBUTE_SENSORS m_hNextAI = (*pNext)->m_hObject; bUpdateDistributedSensors = false; #endif } } }
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 ); } }