openmohaa/code/fgame/actorenemy.cpp

563 lines
16 KiB
C++
Raw Normal View History

2016-03-27 11:49:47 +02:00
/*
===========================================================================
Copyright (C) 2015 the OpenMoHAA team
This file is part of OpenMoHAA source code.
OpenMoHAA source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
OpenMoHAA source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// actorenemy.cpp:
#include "actorenemy.h"
#include "worldspawn.h"
2018-08-29 14:41:48 +02:00
#include "sentient.h"
#include "actor.h"
2016-03-27 11:49:47 +02:00
2023-10-12 20:30:27 +02:00
float ActorEnemy::UpdateLMRF(Actor *pSelf, bool *pbInFovAndRange, bool *pbVisible)
2016-03-27 11:49:47 +02:00
{
2023-10-15 17:11:20 +02:00
float fMaxRange, fRange, fRangeScale, fNormalizedRange;
float fForward;
float fFovScale;
float fMinSightTime;
float fLMRF;
float fFarPlane;
2023-10-12 20:30:27 +02:00
Vector vDelta;
2023-10-15 17:11:20 +02:00
float fObfuscation;
2016-03-27 11:49:47 +02:00
2023-10-12 20:30:27 +02:00
*pbInFovAndRange = false;
*pbVisible = false;
2023-10-15 17:11:20 +02:00
vDelta = pSelf->VirtualEyePosition() - GetEnemy()->origin;
vDelta[2] = 0;
2023-10-12 20:30:27 +02:00
2023-10-15 17:11:20 +02:00
fRange = vDelta.lengthXYSquared();
fMaxRange = pSelf->m_fSight;
2023-10-12 20:30:27 +02:00
2023-10-15 17:11:20 +02:00
if (world->farplane_distance > 0) {
fFarPlane = world->farplane_distance * 0.828f;
2023-10-12 20:30:27 +02:00
2023-10-15 17:11:20 +02:00
if (fMaxRange > fFarPlane) {
fMaxRange = fFarPlane;
2023-10-12 20:30:27 +02:00
}
}
2023-10-15 17:11:20 +02:00
if (fRange > Square(fMaxRange)) {
2023-10-12 20:30:27 +02:00
return 8.0;
}
2023-10-15 17:11:20 +02:00
fForward = sqrt(fRange);
2023-10-12 20:30:27 +02:00
2023-10-15 17:11:20 +02:00
fMinSightTime = -DotProduct2D(pSelf->m_vEyeDir, vDelta);
if (fMinSightTime < 0) {
2023-10-12 20:30:27 +02:00
return 8.0;
}
2023-10-15 17:11:20 +02:00
fMinSightTime += 128;
if (pSelf->m_fFovDot * fForward > fMinSightTime) {
2023-10-12 20:30:27 +02:00
return 8.0;
}
*pbInFovAndRange = true;
if (!pSelf->CanSee(m_pEnemy, 0, 0, false)) {
return 8.0;
}
2023-10-15 17:11:20 +02:00
// Added in 2.0.
// Check for obfuscation
fObfuscation = G_VisualObfuscation(pSelf->VirtualEyePosition(), m_pEnemy->EyePosition());
if (fObfuscation >= 1.f) {
return 8.0;
}
*pbVisible = true;
fFovScale = (fMinSightTime / (fForward + 128.0) * -1.3 - (pSelf->m_fFovDot * 0.2 - 1.5)) / (1.0 - pSelf->m_fFovDot);
fRangeScale = fForward / fMaxRange;
fNormalizedRange = (((fRangeScale * 16.0 + -16.0) * fRangeScale + -1.0) * fRangeScale + 7.0) * fRangeScale;
fNormalizedRange = fNormalizedRange / 3.0;
fLMRF = Square(m_pEnemy->stealthMovementScale * fNormalizedRange) * (fForward + 128.0) / fMinSightTime;
fLMRF *= pSelf->m_fNoticeTimeScale * g_ai_noticescale->value;
if (fLMRF < fFovScale) {
return fFovScale;
2023-10-12 20:30:27 +02:00
}
2023-10-15 17:11:20 +02:00
2023-10-12 20:30:27 +02:00
return fLMRF;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
float ActorEnemy::UpdateVisibility(Actor *pSelf, bool *pbInFovAndRange, bool *pbVisible)
2016-03-27 11:49:47 +02:00
{
2023-10-12 20:18:22 +02:00
float fLMRF, fFrameTime;
fFrameTime = level.time - m_fLastLookTime;
m_fLastLookTime = level.time;
fLMRF = UpdateLMRF(pSelf, pbInFovAndRange, pbVisible);
if (fLMRF < 8.0) {
m_fVisibility += fFrameTime / fLMRF;
2023-10-15 17:11:20 +02:00
} else if (m_fVisibility < 1.0) {
m_fVisibility -= fFrameTime * 0.25;
if (m_fVisibility < 0.0) {
m_fVisibility = 0.0;
2023-10-12 20:18:22 +02:00
}
}
m_fTotalVisibility = m_fVisibility + GetEnemy()->m_fPlayerSightLevel;
if (m_fTotalVisibility > 1) {
m_fVisibility = 1;
m_fTotalVisibility = 1;
}
return m_fTotalVisibility;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
int ActorEnemy::UpdateThreat(Actor *pSelf)
2016-03-27 11:49:47 +02:00
{
2023-10-15 17:11:20 +02:00
static float fRangeThreatSquared[] = {
Square(2048),
Square(1400),
Square(1100),
Square(916),
Square(784),
Square(683),
Square(600),
Square(529),
Square(466),
Square(410),
Square(357),
Square(305),
Square(254),
Square(200),
Square(137)};
static int iWeaponThreat[7][5] = {
{5, 3, 1, 1, 1},
{8, 6, 4, 2, 1},
{10, 9, 7, 8, 4},
{12, 10, 8, 4, 3},
{12, 12, 9, 7, 4},
{12, 10, 5, 2, 1},
{10, 12, 10, 7, 5}
};
int iWeapon;
int iZone;
Vector vDelta;
int i;
2023-10-12 20:18:22 +02:00
m_iThreat = 0;
m_fCurrentRangeSquared = 1e38f;
2023-10-15 17:11:20 +02:00
if (m_pEnemy->m_bIsDisguised || m_fTotalVisibility < 0.999f || level.inttime < m_iNextEnemyTime) {
2023-10-12 20:18:22 +02:00
return m_iThreat;
}
m_iThreat = 10000;
if (m_bVisible == true) {
m_iThreat = 10500;
}
vDelta = m_pEnemy->origin - pSelf->origin;
m_fCurrentRangeSquared = vDelta.lengthSquared();
2023-10-15 17:11:20 +02:00
if (m_fCurrentRangeSquared < Square(256)) {
2023-10-12 20:18:22 +02:00
iZone = 0;
2023-10-15 17:11:20 +02:00
} else if (m_fCurrentRangeSquared < Square(768)) {
iZone = 1;
} else if (m_fCurrentRangeSquared < Square(1280)) {
iZone = 2;
} else if (m_fCurrentRangeSquared < Square(2048)) {
iZone = 3;
} else {
iZone = 4;
2023-10-12 20:18:22 +02:00
}
Weapon *pEnemyWeapon = m_pEnemy->GetActiveWeapon(WEAPON_MAIN);
iWeapon = 0;
if (pEnemyWeapon) {
int iWeapClass = pEnemyWeapon->GetWeaponClass();
if (iWeapClass & WEAPON_CLASS_PISTOL) {
iWeapon = 1;
} else if (iWeapClass & WEAPON_CLASS_RIFLE) {
iWeapon = 2;
} else if (iWeapClass & WEAPON_CLASS_SMG) {
iWeapon = 3;
} else if (iWeapClass & WEAPON_CLASS_MG) {
iWeapon = 4;
} else if (iWeapClass & WEAPON_CLASS_GRENADE) {
iWeapon = 5;
} else {
iWeapon = 6;
}
}
2023-10-15 17:11:20 +02:00
for (i = 0; i < ARRAY_LEN(fRangeThreatSquared) && fRangeThreatSquared[i] > m_fCurrentRangeSquared; i++) {}
2023-10-12 20:18:22 +02:00
2023-10-15 17:11:20 +02:00
m_iThreat += iWeaponThreat[iWeapon][iZone] + m_pEnemy->m_iThreatBias + i;
2023-10-12 20:18:22 +02:00
float fMinSafeDistSquared = 1.21 * pSelf->m_fMinDistanceSquared + 16384;
if (m_fCurrentRangeSquared < fMinSafeDistSquared) {
2023-10-15 17:11:20 +02:00
m_iThreat += 500 - (sqrt(m_fCurrentRangeSquared / fMinSafeDistSquared) * 500);
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:11:20 +02:00
vec2_t vLine;
VectorSub2D(m_vLastKnownPos, pSelf->origin, vLine);
float fDot = DotProduct2D(vLine, m_vLastKnownPos);
Sentient *pSquadMate;
for (pSquadMate = m_pEnemy->m_pNextSquadMate; pSquadMate != m_pEnemy; pSquadMate = pSquadMate->m_pNextSquadMate) {
2023-10-12 20:18:22 +02:00
if (fDot > DotProduct2D(vLine, pSquadMate->origin)) {
m_iThreat -= 4;
}
}
2023-10-15 17:11:20 +02:00
if (m_pEnemy->IsSubclassOfActor()) {
Actor *pActorEnemy = static_cast<Actor *>(m_pEnemy.Pointer());
if (pActorEnemy->m_ThinkState == THINKSTATE_PAIN) {
m_iThreat -= 2;
}
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:11:20 +02:00
fDot = vDelta * pSelf->orientation[0];
if (fDot > 0) {
if (m_fCurrentRangeSquared * 0.5 >= Square(fDot) && m_fCurrentRangeSquared * 0.5 > Square(fDot)) {
2023-10-12 20:18:22 +02:00
m_iThreat++;
}
} else {
2023-10-15 17:11:20 +02:00
if (m_fCurrentRangeSquared * 0.5 > Square(fDot)) {
m_iThreat++;
2023-10-12 20:18:22 +02:00
}
}
int iEnemyDiscount = m_pEnemy->m_iAttackerCount;
if (m_pEnemy == pSelf->m_Enemy) {
iEnemyDiscount -= 2;
if (level.inttime < pSelf->m_iEnemyChangeTime + 1000) {
m_iThreat += 5;
}
}
if (iEnemyDiscount > 4) {
iEnemyDiscount = 4;
}
m_iThreat -= iEnemyDiscount;
if (m_pEnemy == pSelf->m_pLastAttacker) {
m_iThreat += 5;
}
if (m_pEnemy == pSelf->m_FavoriteEnemy) {
m_iThreat += 250;
}
return m_iThreat;
2016-03-27 11:49:47 +02:00
}
ActorEnemySet::ActorEnemySet()
{
2023-10-12 20:30:27 +02:00
m_iCheckCount = 0;
m_pCurrentEnemy = NULL;
2023-10-12 20:18:22 +02:00
m_iCurrentThreat = 0;
m_fCurrentVisibility = 0.0;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
ActorEnemy *ActorEnemySet::AddPotentialEnemy(Sentient *pEnemy)
{
ActorEnemy NewEnemy;
2018-09-05 16:55:10 +02:00
2023-10-12 20:18:22 +02:00
if (pEnemy->IsDead() || pEnemy->m_iThreatBias == THREATBIAS_IGNOREME) {
return NULL;
}
2018-09-05 16:55:10 +02:00
2023-10-12 20:18:22 +02:00
for (int i = 0; i < m_Enemies.NumObjects(); i++) {
ActorEnemy *pActorEnemy = &m_Enemies[i];
if (pActorEnemy->m_pEnemy == pEnemy) {
pActorEnemy->m_iAddTime = level.inttime;
return pActorEnemy;
}
}
2018-09-05 16:55:10 +02:00
2023-10-15 17:11:20 +02:00
NewEnemy.m_iAddTime = level.inttime;
NewEnemy.m_iNextEnemyTime = 0;
NewEnemy.m_fLastLookTime = level.time;
NewEnemy.m_fVisibility = 0.0;
NewEnemy.m_fTotalVisibility = 0.0;
NewEnemy.m_iThreat = 0;
NewEnemy.m_pEnemy = pEnemy;
2023-10-12 20:18:22 +02:00
NewEnemy.m_fCurrentRangeSquared = 1e38f;
NewEnemy.m_vLastKnownPos = vec_zero;
2023-10-15 17:11:20 +02:00
NewEnemy.m_iLastSightChangeTime = 0;
NewEnemy.m_bVisible = false;
2018-09-05 16:55:10 +02:00
2023-10-15 17:11:20 +02:00
int index = m_Enemies.AddObject(NewEnemy);
return m_Enemies.AddressOfObjectAt(index);
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
void ActorEnemySet::FlagBadEnemy(Sentient *pEnemy)
2016-03-27 11:49:47 +02:00
{
2023-10-15 17:11:20 +02:00
ActorEnemy *pActorEnemy = NULL;
for (int i = 1; i <= m_Enemies.NumObjects(); i++) {
if (m_Enemies.ObjectAt(i).m_pEnemy == pEnemy) {
pActorEnemy = m_Enemies.AddressOfObjectAt(i);
2023-10-12 20:18:22 +02:00
break;
}
2023-10-15 17:11:20 +02:00
}
2023-10-12 20:18:22 +02:00
2023-10-15 17:11:20 +02:00
if (!pActorEnemy) {
return;
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:11:20 +02:00
// Added in 2.0.
// Set the reaction time
pActorEnemy->m_iNextEnemyTime = level.inttime + 5000;
2023-10-12 20:18:22 +02:00
2023-10-15 17:11:20 +02:00
pActorEnemy->m_fLastLookTime = level.time;
pActorEnemy->m_fVisibility = 0.0;
pActorEnemy->m_fTotalVisibility = 0.0;
pActorEnemy->m_iThreat = 0;
2023-10-12 20:18:22 +02:00
pActorEnemy->m_iLastSightChangeTime = level.inttime;
2023-10-15 17:11:20 +02:00
pActorEnemy->m_bVisible = false;
2023-10-12 20:18:22 +02:00
if (pEnemy == m_pCurrentEnemy) {
2023-10-15 17:11:20 +02:00
m_pCurrentEnemy = NULL;
2023-10-12 20:18:22 +02:00
m_fCurrentVisibility = 0.0;
m_iCurrentThreat = 0;
}
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
void ActorEnemySet::CheckEnemies(Actor *pSelf)
2016-03-27 11:49:47 +02:00
{
2023-10-12 20:18:22 +02:00
float fVisibility;
2023-10-15 17:11:20 +02:00
int iThreat;
int i;
int nChecked;
bool bInFovAndRange;
bool bVisible;
float fRangeSquared;
2023-10-12 20:18:22 +02:00
ActorEnemy *pActorEnemy;
2023-10-15 17:11:20 +02:00
for (i = 1; i <= m_Enemies.NumObjects();) {
2023-10-12 20:18:22 +02:00
pActorEnemy = &m_Enemies[i - 1];
2023-10-15 17:11:20 +02:00
if (!pActorEnemy->GetEnemy() || pActorEnemy->GetEnemy()->m_Team == pSelf->m_Team
|| pActorEnemy->GetEnemy()->IsDead() || level.inttime > pActorEnemy->m_iAddTime + 10000
2024-02-25 19:16:07 +01:00
|| pActorEnemy->GetEnemy()->m_iThreatBias == THREATBIAS_IGNOREME || pActorEnemy->GetEnemy()->IsDisabled()) {
2023-10-12 20:18:22 +02:00
m_Enemies.RemoveObjectAt(i);
2023-10-15 17:11:20 +02:00
} else {
i++;
2023-10-12 20:18:22 +02:00
}
}
if (!m_Enemies.NumObjects()) {
m_iCurrentThreat = 0;
2023-10-15 17:11:20 +02:00
m_pCurrentEnemy = NULL;
return;
}
bInFovAndRange = false;
for (nChecked = 0; nChecked < m_Enemies.NumObjects() && !bInFovAndRange; nChecked++) {
m_iCheckCount++;
if (m_iCheckCount > m_Enemies.NumObjects()) {
m_iCheckCount = 1;
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:11:20 +02:00
pActorEnemy = &m_Enemies[m_iCheckCount - 1];
2023-10-12 20:18:22 +02:00
2023-10-15 17:11:20 +02:00
fVisibility = pActorEnemy->UpdateVisibility(pSelf, &bInFovAndRange, &bVisible);
if (fVisibility > 0) {
if (fVisibility >= m_fCurrentVisibility) {
m_fCurrentVisibility = fVisibility;
m_pCurrentEnemy = pActorEnemy->GetEnemy();
} else if (pActorEnemy->m_pEnemy == m_pCurrentEnemy) {
m_fCurrentVisibility = fVisibility;
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:11:20 +02:00
if (g_showawareness->integer) {
Com_Printf(
"ent #%3i: enemy #%i: awareness = %5.1f%%, threat = %i\n",
pSelf->entnum,
pActorEnemy->GetEnemy()->entnum,
(fVisibility * 100.0),
2023-10-15 17:11:20 +02:00
0
);
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:11:20 +02:00
} else if (pActorEnemy->m_pEnemy == m_pCurrentEnemy) {
m_iCurrentThreat = 0;
m_pCurrentEnemy = NULL;
m_fCurrentVisibility = 0;
}
2023-10-12 20:18:22 +02:00
2023-10-15 17:11:20 +02:00
if (bVisible) {
if (!pActorEnemy->m_bVisible) {
pActorEnemy->m_bVisible = true;
pActorEnemy->m_iLastSightChangeTime = level.inttime;
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:11:20 +02:00
pActorEnemy->m_vLastKnownPos = pActorEnemy->m_pEnemy->origin;
} else if (pActorEnemy->m_bVisible) {
pActorEnemy->m_bVisible = false;
pActorEnemy->m_iLastSightChangeTime = level.inttime;
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:11:20 +02:00
}
2023-10-12 20:18:22 +02:00
2023-10-15 17:11:20 +02:00
if (m_pCurrentEnemy && m_pCurrentEnemy->IsDead()) {
m_pCurrentEnemy = NULL;
m_iCurrentThreat = 0;
m_fCurrentVisibility = 0;
}
2023-10-12 20:18:22 +02:00
2023-10-15 17:11:20 +02:00
m_iCurrentThreat = 0;
fRangeSquared = 1e37f;
2023-10-12 20:18:22 +02:00
if (m_fCurrentVisibility >= 0.999f) {
2023-10-15 17:11:20 +02:00
iThreat = 0;
for (i = 1; i <= m_Enemies.NumObjects(); i++) {
pActorEnemy = &m_Enemies.ObjectAt(i);
pActorEnemy->UpdateThreat(pSelf);
if (m_iCurrentThreat >= pActorEnemy->GetThreat()) {
if (m_iCheckCount != pActorEnemy->GetThreat()) {
continue;
}
if (pActorEnemy->GetRangeSquared() < fRangeSquared) {
continue;
2023-10-12 20:18:22 +02:00
}
}
2023-10-15 17:11:20 +02:00
iThreat = pActorEnemy->GetThreat();
m_pCurrentEnemy = pActorEnemy->GetEnemy();
fRangeSquared = pActorEnemy->m_fCurrentRangeSquared;
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:11:20 +02:00
m_iCurrentThreat = iThreat;
}
if ((!m_pCurrentEnemy || !m_pCurrentEnemy->m_bIsDisguised) && m_iCurrentThreat <= 0) {
m_pCurrentEnemy = NULL;
m_iCurrentThreat = 0;
m_fCurrentVisibility = 0;
2023-10-12 20:18:22 +02:00
}
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
bool ActorEnemySet::HasAlternateEnemy(void) const
2016-03-27 11:49:47 +02:00
{
2023-10-15 17:11:20 +02:00
for (int i = 1; i <= m_Enemies.NumObjects(); i++) {
const ActorEnemy& actorEnemy = m_Enemies.ObjectAt(i);
if (actorEnemy.GetVisibility() >= 0.999f && actorEnemy.GetEnemy() != m_pCurrentEnemy) {
2023-10-12 20:18:22 +02:00
return true;
}
}
return false;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
void ActorEnemySet::RemoveAll(void)
2016-03-27 11:49:47 +02:00
{
2023-10-12 20:18:22 +02:00
m_Enemies.ClearObjectList();
2023-10-15 17:11:20 +02:00
m_iCheckCount = 0;
m_pCurrentEnemy = NULL;
2023-10-12 20:18:22 +02:00
m_fCurrentVisibility = 0.0;
m_iCurrentThreat = 0;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
void ActorEnemySet::ConfirmEnemy(Actor *pSelf, Sentient *pEnemy)
2016-03-27 11:49:47 +02:00
{
2023-10-15 17:11:20 +02:00
ActorEnemy *pActorEnemy;
2023-10-12 20:18:22 +02:00
pSelf->m_bEnemyIsDisguised = false;
2023-10-15 17:11:20 +02:00
pActorEnemy = ActorEnemySet::AddPotentialEnemy(pEnemy);
if (!pActorEnemy) {
return;
}
// Added in 2.0.
// Ignore if below reaction time
if (level.inttime < pActorEnemy->m_iNextEnemyTime) {
return;
}
pActorEnemy->m_fVisibility = 1.0;
pActorEnemy->m_fTotalVisibility = 1.0;
pActorEnemy->m_vLastKnownPos = pEnemy->origin;
if (m_fCurrentVisibility < 1.0) {
m_iCurrentThreat = pActorEnemy->UpdateThreat(pSelf);
m_fCurrentVisibility = 1.0;
m_pCurrentEnemy = pEnemy;
2023-10-12 20:18:22 +02:00
}
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
void ActorEnemySet::ConfirmEnemyIfCanSeeSharerOrEnemy(Actor *pSelf, Actor *pSharer, Sentient *pEnemy)
2016-03-27 11:49:47 +02:00
{
2023-10-15 17:11:20 +02:00
ActorEnemy *pActorEnemy;
2023-10-12 20:18:22 +02:00
pSelf->m_bEnemyIsDisguised = false;
2023-10-15 17:11:20 +02:00
pActorEnemy = ActorEnemySet::AddPotentialEnemy(pEnemy);
if (!pActorEnemy) {
return;
}
// Added in 2.0.
// Ignore if below reaction time
if (level.inttime < pActorEnemy->m_iNextEnemyTime) {
return;
}
if (pActorEnemy->m_fTotalVisibility >= 1.f) {
pActorEnemy->m_vLastKnownPos = pEnemy->origin;
return;
}
if (!pActorEnemy->m_bVisible
&& !pSelf->CanSee(pSharer, pSelf->m_bSilent ? 90 : 0, world->farplane_distance * 0.828f, false)) {
return;
}
pActorEnemy->m_fVisibility = 1.0;
pActorEnemy->m_fTotalVisibility = 1.0;
pActorEnemy->m_vLastKnownPos = pEnemy->origin;
if (m_fCurrentVisibility < 1.0) {
m_iCurrentThreat = pActorEnemy->UpdateThreat(pSelf);
m_fCurrentVisibility = 1.0;
m_pCurrentEnemy = pEnemy;
2023-10-12 20:18:22 +02:00
}
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
bool ActorEnemySet::CaresAboutPerfectInfo(Sentient *pEnemy)
2016-03-27 11:49:47 +02:00
{
2023-10-12 20:18:22 +02:00
ActorEnemy *pActorEnemy = ActorEnemySet::AddPotentialEnemy(pEnemy);
2023-10-15 17:11:20 +02:00
if (!pActorEnemy) {
return false;
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:11:20 +02:00
// Added in 2.0.
// Ignore if below reaction time
if (level.inttime < pActorEnemy->m_iNextEnemyTime) {
return false;
}
if (pActorEnemy->m_fTotalVisibility < 1.0f) {
return true;
}
if ((pEnemy->origin - pActorEnemy->m_vLastKnownPos).lengthSquared() <= Square(512)) {
return false;
}
return true;
2016-03-27 11:49:47 +02:00
}