void CAISenseRecorderAbstract::CopySenseRecord(AISenseRecord* pOrigSenseRecord) { if( !pOrigSenseRecord ) { ASSERT( pOrigSenseRecord != LTNULL ); return; } // Find sense record for stimulus. AISENSE_RECORD_MAP::iterator it = m_mapSenseRecords.find( pOrigSenseRecord->eSenseType ); ASSERT(it != m_mapSenseRecords.end()); AISenseRecord* pSenseRecord = it->second; // If sense was already updated this cycle, do not copy over it. if( pSenseRecord->nCycle == pOrigSenseRecord->nCycle ) { return; } // Mark the sense as being updated this cycle. The recorder can look at the // cycle stamp later to determine which senses were updated during one cycle. pSenseRecord->nCycle = pOrigSenseRecord->nCycle; // Keep a pointer to the bute file entry for the stimulus. pSenseRecord->pAIBM_Last_Stimulus = pOrigSenseRecord->pAIBM_Last_Stimulus; // Mark the timestamp of the stimulating sense. pSenseRecord->fLastStimulationTime = pOrigSenseRecord->fLastStimulationTime; // Record info about stimulus. pSenseRecord->hLastStimulusSource = pOrigSenseRecord->hLastStimulusSource; pSenseRecord->hLastStimulusTarget = pOrigSenseRecord->hLastStimulusTarget; pSenseRecord->eLastTargetMatchID = pOrigSenseRecord->eLastTargetMatchID; pSenseRecord->vLastStimulusPos = pOrigSenseRecord->vLastStimulusPos; pSenseRecord->vLastStimulusDir = pOrigSenseRecord->vLastStimulusDir; pSenseRecord->nLastStimulusAlarmLevel = pOrigSenseRecord->nLastStimulusAlarmLevel; pSenseRecord->eLastStimulusID = pOrigSenseRecord->eLastStimulusID; // Randomize reaction delay time. // Do not reset the timer if stimulation already started. if( pSenseRecord->fCurStimulation <= 0.f ) { pSenseRecord->fReactionDelayTime = GetRandom( pSenseRecord->pAIBM_Last_Stimulus->rngReactionDelay.GetMin(), pSenseRecord->pAIBM_Last_Stimulus->rngReactionDelay.GetMax() ); pSenseRecord->fReactionDelayTimer = 0.f; } // Returns true if sense has reached full stimulation. // Force full stimulation. IncreaseStimulation(pSenseRecord, 9999999.99f ); }
LTBOOL CAISenseHearEnemyFootstep::Update(HOBJECT hStimulus, LTFLOAT fTimeDelta) { if ( !IsCharacter(hStimulus) ) return LTFALSE; CCharacter* pChar = (CCharacter*)g_pLTServer->HandleToObject(hStimulus); CharMoveInfo info; pChar->GetLastMoveInfo(info); if ( info.fTime > m_fStimulationTime && g_pLTServer->GetTime() > info.fTime && g_pLTServer->GetTime() < info.fTime + 0.50f ) { LTVector vMovementPos; g_pLTServer->GetObjectPos(hStimulus, &vMovementPos); LTFLOAT fDistance = VEC_DIST(vMovementPos, m_pAI->GetPosition()); LTFLOAT fMovementNoiseDistance = g_pAIButeMgr->GetSenses()->fEnemyMovementNoiseDistance; fMovementNoiseDistance *= info.fVolume; if ( fDistance < (m_fDistance + fMovementNoiseDistance) ) { IncreaseStimulation(fTimeDelta); // Record the timestamp m_fTimestamp = info.fTime; // Record the stimulus position m_vStimulusPosition = vMovementPos; return LTTRUE; } } return LTFALSE; }
LTBOOL CAISenseSeeEnemyFlashlight::Update(HOBJECT hStimulus, LTFLOAT fTimeDelta) { if ( !IsPlayer(hStimulus) ) return LTFALSE; CPlayerObj* pPlayer = (CPlayerObj*)g_pLTServer->HandleToObject(hStimulus); if ( pPlayer->IsFlashlightOn() ) { const LTVector& vPos = pPlayer->GetFlashlightPos(); const static LTFLOAT fRadiusSqr = 40000.0f; LTFLOAT fDistanceSqr = VEC_DISTSQR(m_pAI->GetPosition(), vPos); if ( fDistanceSqr < (fRadiusSqr) ) { LTFLOAT fRateModifier = (1.0f - fDistanceSqr/m_fDistanceSqr); IncreaseStimulation(fTimeDelta, (fRateModifier)); return LTTRUE; } } return LTFALSE; }
LTBOOL CAISenseRecorderAbstract::UpdateSenseRecord(CAIStimulusRecord* pStimulusRecord, uint32 nCycle) { if( !pStimulusRecord ) { ASSERT(pStimulusRecord != LTNULL); return LTFALSE; } // Find sense record for stimulus. AISENSE_RECORD_MAP::iterator it = m_mapSenseRecords.find(pStimulusRecord->m_pAIBM_Stimulus->eSenseType); ASSERT(it != m_mapSenseRecords.end()); AISenseRecord* pSenseRecord = it->second; // Only sense more recent stimuli, if flag is set to ignore old stimulus. if( pStimulusRecord->m_pAIBM_Stimulus->bIgnoreOldStimulus && ( pSenseRecord->fLastStimulationTime >= pStimulusRecord->m_fTimeStamp ) ) { return LTFALSE; } LTFLOAT fRateModifier = 1.0f; // Do additional expensive checks here. (e.g. Ray casts). if(!HandleSpecificStimuli(pStimulusRecord, &fRateModifier)) { return LTFALSE; } // Mark the sense as being updated this cycle. The recorder can look at the // cycle stamp later to determine which senses were updated during one cycle. pSenseRecord->nCycle = nCycle; // Keep a pointer to the bute file entry for the stimulus. AIBM_Stimulus* pAIBM_Stimulus = pStimulusRecord->m_pAIBM_Stimulus; pSenseRecord->pAIBM_Last_Stimulus = pAIBM_Stimulus; // Mark the timestamp of the stimulating sense. pSenseRecord->fLastStimulationTime = pStimulusRecord->m_fTimeStamp; // Record info about stimulus. pSenseRecord->hLastStimulusSource = ( HOBJECT )pStimulusRecord->m_hStimulusSource; pSenseRecord->hLastStimulusTarget = ( HOBJECT )pStimulusRecord->m_hStimulusTarget; pSenseRecord->eLastTargetMatchID = pStimulusRecord->m_eTargetMatchID; pSenseRecord->vLastStimulusPos = pStimulusRecord->m_vStimulusPos; pSenseRecord->vLastStimulusDir = pStimulusRecord->m_vStimulusDir; pSenseRecord->nLastStimulusAlarmLevel = pStimulusRecord->m_nStimulusAlarmLevel; pSenseRecord->eLastStimulusID = pStimulusRecord->m_eStimulusID; // Randomize reaction delay time. // Do not reset the timer if stimulation already started. if( pSenseRecord->fCurStimulation <= 0.f ) { pSenseRecord->fReactionDelayTime = GetRandom( pAIBM_Stimulus->rngReactionDelay.GetMin(), pAIBM_Stimulus->rngReactionDelay.GetMax() ); pSenseRecord->fReactionDelayTimer = 0.f; } // Returns true if sense has reached full stimulation. return IncreaseStimulation(pSenseRecord, fRateModifier); }
LTBOOL CAISenseSeeEnemy::Update(HOBJECT hStimulus, LTFLOAT fTimeDelta) { if ( !IsCharacter(hStimulus) ) return LTFALSE; if ( m_pAI->GetCharacterClass() == NEUTRAL ) { // If we're innocent, we only consider someone an enemy if they have a gun CCharacter* pCharacter = (CCharacter*)g_pLTServer->HandleToObject(hStimulus); if ( !pCharacter->HasDangerousWeapon() ) { return LTFALSE; } } // Instead of looking right at the center of the target, we at a grid of points. // The grid is a plane with normal equal to the forward vector of the object, // in the center of the object, clipped to the objects dims. We scan the grid // at a given resolution and simply advance our scan col/row every frame. Note // that the grid is aligned with the objects rotation, not the bounding boxes, // since all the bounding boxes are axis aligned. int nXRange = m_rngGridX.GetMax() - m_rngGridX.GetMin(); int nYRange = m_rngGridY.GetMax() - m_rngGridY.GetMin(); LTVector vDims; g_pLTServer->GetObjectDims(hStimulus, &vDims); LTFLOAT fX = vDims.x * ((LTFLOAT)m_nGridX/(LTFLOAT)nXRange); LTFLOAT fY = vDims.y * ((LTFLOAT)m_nGridY/(LTFLOAT)nYRange); LTVector vPosition; g_pLTServer->GetObjectPos(hStimulus, &vPosition); LTRotation rRot; g_pLTServer->GetObjectRotation(hStimulus, &rRot); LTVector vUp, vRight, vForward; g_pLTServer->GetRotationVectors(&rRot, &vUp, &vRight, &vForward); vPosition += vRight*fX; vPosition += vUp*fY; // Update the point LTFLOAT fDistanceSqr; LTBOOL bVisible; if ( m_pAI->CanSeeThrough() ) { bVisible = m_pAI->IsObjectPositionVisibleFromEye(CAI::SeeThroughFilterFn, CAI::SeeThroughPolyFilterFn, hStimulus, vPosition, (m_fDistanceSqr), LTTRUE, &fDistanceSqr); } else { bVisible = m_pAI->IsObjectPositionVisibleFromEye(CAI::DefaultFilterFn, NULL, hStimulus, vPosition, (m_fDistanceSqr), LTTRUE, &fDistanceSqr); } if ( bVisible ) { if ( fDistanceSqr > g_pAIButeMgr->GetSenses()->fInstantSeeDistanceSqr ) { LTFLOAT fRateModifier = (1.0f - fDistanceSqr/m_fDistanceSqr); IncreaseStimulation(fTimeDelta, (fRateModifier)); } else { IncreaseStimulation(fTimeDelta, 99999999.0f); } } // Update our grid col/row values if ( ++m_nGridX > m_rngGridX.GetMax() ) { m_nGridX = m_rngGridX.GetMin(); if ( ++m_nGridY > m_rngGridY.GetMax() ) { m_nGridY = m_rngGridY.GetMin(); } } return bVisible; }