ef2-sdk/dlls/game/actor_enemymanager.cpp

1075 lines
24 KiB
C++
Raw Permalink Normal View History

2003-11-05 00:00:00 +00:00
//-----------------------------------------------------------------------------
//
// $Logfile:: /EF2/Code/DLLs/game/actor_enemymanager.cpp $
// $Revision:: 41 $
// $Author:: Singlis $
// $Date:: 9/26/03 2:35p $
//
// Copyright (C) 2001 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
//
#include "_pch_cpp.h"
#include "actor_enemymanager.h"
#include "player.h"
#include "object.h"
//======================================
// EnemyManager Implementation
//=====================================
//
// Name: EnemyManager()
// Parameters: None
// Description: Constructor
//
EnemyManager::EnemyManager()
{
// Should always use other constructor
gi.Error( ERR_FATAL, "EnemyManager::EnemyManager -- Default Constructor Called" );
}
//
// Name: EnemyManager()
// Parameters: Actor *actor
// Description: Constructor
//
EnemyManager::EnemyManager( Actor *actor )
{
//Initialize our Actor
if ( actor )
act = actor;
else
gi.Error( ERR_DROP, "EnemyManager::EnemyManager -- actor is NULL" );
_lockedOnCurrentEnemy = false;
}
//
// Name: ~EnemyManager()
// Parameters: None
// Description: Destructor
//
EnemyManager::~EnemyManager()
{
}
//
// Name: GetCurrentEnemy()
// Parameters: None
// Description: Returns the _currentEnemy
//
EntityPtr EnemyManager::GetCurrentEnemy()
{
if ( act->forcedEnemy )
{
if ( act->forcedEnemy->health <= 0 )
{
act->forcedEnemy = NULL;
_lockedOnCurrentEnemy = false;
return _currentEnemy;
}
else
return act->forcedEnemy;
}
if ( !_currentEnemy )
FindHighestHateEnemy();
return _currentEnemy;
}
//
// Name: SetCurrentEnemy()
// Parameters: Entity *enemy
// Description: sets _currentEnemy
//
void EnemyManager::SetCurrentEnemy( Entity *enemy )
{
if ( enemy )
_currentEnemy = enemy;
else
{
_lockedOnCurrentEnemy = false;
}
}
EntityPtr EnemyManager::GetAlternateTarget()
{
return _alternateTarget;
}
void EnemyManager::SetAlternateTarget( Entity *target )
{
_alternateTarget = target;
}
//
// Name: FindHightestHateEnemy()
// Parameters: None
// Description: Sets the _currentEnemy to the highest enemy on the hate list
//
void EnemyManager::FindHighestHateEnemy()
{
float hateValue = 0;
HateListEntry_t listIndex;
float hateFactor;
if ( IsLockedOnCurrentEnemy() )
return;
for ( int i = _hateList.NumObjects() ; i > 0 ; i-- )
{
hateFactor = 100;
listIndex = _hateList.ObjectAt( i );
listIndex.hate = listIndex.hate * ( 1 / listIndex.lastDistance );
if ( !listIndex.enemy )
{
_hateList.RemoveObjectAt( i );
continue;
}
//If the enemy is a player, make sure to modify our hate
if ( listIndex.enemy->isSubclassOf( Sentient ) && !act->GetActorFlag(ACTOR_FLAG_UPDATE_HATE_WITH_ATTACKERS) )
{
Sentient *theEnemy;
theEnemy = (Sentient*)(Entity*)listIndex.enemy;
hateFactor *= theEnemy->GetHateModifier();
}
listIndex.hate *= hateFactor;
if ( listIndex.hate >= hateValue && listIndex.hate > 0.0 )
{
_currentEnemy = listIndex.enemy;
hateValue = listIndex.hate;
}
}
}
//
// Name: FindClosestEnemy()
// Parameters: None
// Description: Sets the _currentEnemy to the enemy closest to the actor
//
void EnemyManager::FindClosestEnemy()
{
float distance = 99999999.9;
for ( int i = 1 ; i <= _hateList.NumObjects() ; i++ )
{
EntityPtr enemy;
HateListEntry_t listIndex;
listIndex = _hateList.ObjectAt( i );
if ( !act->combatSubsystem->CanAttackTarget( listIndex.enemy ) )
continue;
if ( listIndex.lastDistance < distance )
{
_currentEnemy = listIndex.enemy;
distance = listIndex.lastDistance;
}
}
}
void EnemyManager::FindNextEnemy()
{
HateListEntry_t listIndex;
float hateValue;
hateValue = 0;
for ( int i = 1 ; i <= _hateList.NumObjects() ; i++ )
{
listIndex = _hateList.ObjectAt( i );
if ( listIndex.hate <= _currentEnemyHate && listIndex.hate > hateValue )
{
hateValue = listIndex.hate;
_lastEnemy = _currentEnemy;
_currentEnemy = listIndex.enemy;
_currentEnemyHate = hateValue;
}
}
}
//
// Name: ClearCurrentEnemy()
// Parameters: None
// Description: sets the _currentEnemy to NULL
//
void EnemyManager::ClearCurrentEnemy()
{
_lockedOnCurrentEnemy = false;
_currentEnemy = NULL;
}
//
// Name: ClearHateList()
// Parameters: None
// Description: Wipes out the hate list
//
void EnemyManager::ClearHateList()
{
for ( int i = _hateList.NumObjects() ; i > 0 ; i-- )
{
_hateList.RemoveObjectAt( i );
}
_hateList.FreeObjectList();
}
//
// Name: Likes()
// Parameters: Entity *ent
// Description: Checks if Actor likes the entity
//
qboolean EnemyManager::Likes( Entity *ent )
{
Actor *actor;
if ( !ent )
return false;
if ( ent->isClient() )
{
return ( act->actortype == IS_FRIEND );
}
if ( act->actortype == IS_MONSTER )
{
// Monsters don't like anyone
return false;
}
if ( ent->isSubclassOf( Actor ) )
{
actor = ( Actor * )ent;
if ( actor->enemytype == act->enemytype )
return true;
if ( actor->actortype != act->actortype )
return false;
else if ( act->actortype == IS_FRIEND )
return true;
}
return false;
}
//
// Name: Hates()
// Parameters: Entity *ent
// Description: Checks if Actor hates the entity
//
qboolean EnemyManager::Hates( Entity *ent )
{
Actor *actor;
if ( !ent )
return false;
if ( ent->isClient() )
{
return ( act->actortype != IS_CIVILIAN ) && (( act->actortype != IS_FRIEND ) && ( act->actortype != IS_TEAMMATE));
}
else if ( ent->isSubclassOf( Actor ) && ( act->actortype != IS_INANIMATE ) )
{
actor = ( Actor * )ent;
if ( ( actor->actortype <= IS_ENEMY ) && ( act->actortype <= IS_ENEMY ) )
{
return false;
}
if ( ( actor->actortype == IS_FRIEND ) && ( act->actortype <= IS_ENEMY ) )
{
return true;
}
if ( ( actor->actortype == IS_TEAMMATE ) && ( act->actortype <= IS_ENEMY ) )
{
return true;
}
if ( ( actor->actortype <= IS_ENEMY ) && ( act->actortype == IS_FRIEND ) )
{
return true;
}
if ( ( actor->actortype <= IS_ENEMY ) && ( act->actortype == IS_TEAMMATE ) )
{
return true;
}
if ( ( actor->actortype == IS_TEAMMATE ) && ( act->actortype == IS_TEAMMATE ) )
{
return false;
}
}
return false;
}
//
// Name: IsValidEnemy
// Parameters: Entity *enemy
// Description: Checks if the passed in entity is a valid target or not
//
qboolean EnemyManager::IsValidEnemy( Entity *enemy )
{
if ( !enemy || ( enemy == world ) || ( enemy == act ) || ( enemy->flags & FL_NOTARGET ) || ( enemy->takedamage == DAMAGE_NO ) || enemy->deadflag )
return false;
if ( !Hates( enemy ) )
return false;
if ( !CanAttack( enemy ) )
return false;
if ((enemy->edict->s.renderfx & RF_DONTDRAW) )
return false;
return true;
}
//
// Name: CanAttack
// Parameters: Entity *ent
// Description: Checks if the actor is allowed to attack the passed in entity
//
qboolean EnemyManager::CanAttack( Entity *ent )
{
if ( !ent )
return false;
if ( act->targetType == ATTACK_ANY )
return true;
if ( ent->isSubclassOf( Player ) && ( act->targetType == ATTACK_PLAYER_ONLY ) )
return true;
if ( ent->isSubclassOf( Actor ) && ( act->targetType == ATTACK_ACTORS_ONLY ) )
return true;
if ( ent->isSubclassOf ( LevelInteractionTrigger ) && ( act->targetType == ATTACK_LEVEL_INTERACTION ) )
return true;
return false;
}
//
// Name: CanAttackAnyEnemy
// Parameters: None
// Description: Checks if we can shoot any of our enemies in our list
qboolean EnemyManager::CanAttackAnyEnemy()
{
HateListEntry_t *listIndex;
Entity *target;
for ( int i = 1 ; i <= _hateList.NumObjects() ; i++ )
{
listIndex = &_hateList.ObjectAt( i );
target = listIndex->enemy;
if ( target )
{
if ( act->combatSubsystem->CanAttackTarget( target ) )
return true;
}
}
return false;
}
//
// Name: AdjustHate()
// Parameters: Entity *enemy -- The entity to adjust
// float adjustment -- how much to adjust
// Description: Adjusts the hate value of the enemy
//
void EnemyManager::AdjustHate( Entity *enemy , float adjustment )
{
HateListEntry_t *listIndex;
if ( !enemy )
return;
for ( int i = 1 ; i <= _hateList.NumObjects() ; i++ )
{
listIndex = &_hateList.ObjectAt( i );
if ( listIndex->enemy == enemy )
{
listIndex->hate += adjustment;
if ( listIndex->hate < 0.0f )
listIndex->hate = 0.0f;
return;
}
}
}
//
// Name: AdjustDamageCaused()
// Parameters: Entity *enemy -- The entity to adjust
// float adjustment -- how much to adjust
// Description: Adjusts the damage caused
//
void EnemyManager::AdjustDamageCaused( Entity *enemy , float adjustment )
{
HateListEntry_t listIndex;
if ( !enemy )
return;
for ( int i = 1 ; i <= _hateList.NumObjects() ; i++ )
{
listIndex = _hateList.ObjectAt( i );
if ( listIndex.enemy == enemy )
{
listIndex.damageCaused += adjustment;
return;
}
}
}
//
// Name: TryToAddToHateList
// Parameters: Entity *enemy
// Description: Checks if the passed in entity should be added to the hate list
// and calls _AddToHateList if it does
//
void EnemyManager::TryToAddToHateList( Entity *enemy )
{
if ( !enemy )
return;
if ( IsValidEnemy( enemy ) && !IsInHateList( enemy ) )
{
if ( !act->combatSubsystem->CanAttackTarget( enemy ) && !CanGetToEntity( enemy ) )
{
return;
}
_AddToHateList( enemy );
}
}
//
// Name: _AddToHateList()
// Parameters: Entity *enemy -- The enemy to add
// Description: Adds the enemy to the hate list
//
void EnemyManager::_AddToHateList( Entity *enemy )
{
HateListEntry_t listIndex;
if ( !enemy )
return;
listIndex.enemy = enemy;
listIndex.damageCaused = 0;
listIndex.hate = DEFAULT_INITIAL_HATE;
listIndex.lastSightTime = level.time ;
listIndex.canSee = false;
//listIndex.lastDistance = -1;
listIndex.nextSightTime = level.time + MIN_SIGHT_DELAY;
UpdateDistance( &listIndex );
_hateList.AddObject(listIndex);
}
//
// Name: IsInHateList()
// Parameters: Entity *enemy
// Description: Checks if enemy is in the hate list
//
qboolean EnemyManager::IsInHateList( Entity *enemy )
{
int index = _findEntityInHateList( enemy );
return index > 0;
}
//----------------------------------------------------------------
// Name: IsLastInHateList
// Class: EnemyManager
//
// Description: Determine if the Entity passed is in the hate list,
// and if it is at the end of the list.
//
// Parameters: Entity* enemy - the entity to look for
//
// Returns: qboolean
//----------------------------------------------------------------
qboolean EnemyManager::IsLastInHateList( Entity* enemy )
{
int index = _findEntityInHateList( enemy );
return index == _hateList.NumObjects();
}
//----------------------------------------------------------------
// Name: _findEntityInHateList
// Class: EnemyManager
//
// Description: Search the hate list for the passed entity.
//
// Parameters: Entity* searchEnt - the entity to look for
//
// Returns: The index of the entity in the list
// 0 means it isn't in the list.
//----------------------------------------------------------------
int EnemyManager::_findEntityInHateList( Entity *searchEnt )
{
if( !searchEnt )
{
return false;
}
// manually iterate through the hatelist
HateListEntry_t listIndex;
for( int i = 1; i <= _hateList.NumObjects(); i++ )
{
listIndex = _hateList.ObjectAt( i );
if ( listIndex.enemy == searchEnt )
{
return i;
}
}
// was not found, return 0
return 0;
}
//----------------------------------------------------------------
// Name: TrivialUpdate
// Class: EnemyManager
//
// Description: Minimal Hatelist update required for Actors
//
// Parameters:
// None
//
// Returns: None
//----------------------------------------------------------------
void EnemyManager::TrivialUpdate()
{
for ( int i = _hateList.NumObjects() ; i > 0 ; i-- )
{
_hateList.ObjectAt( i ).lastDistance = 0.0f;
}
}
//
// Name: Update()
// Parameters: None
// Description: Updates HateListEntry_ts
//
void EnemyManager::Update()
{
HateListEntry_t *listIndex;
for ( int i = _hateList.NumObjects() ; i > 0 ; i-- )
{
listIndex = &_hateList.ObjectAt( i );
//Check if enemy is alive
if ( !act->IsEntityAlive( listIndex->enemy ) )
{
if ( listIndex->enemy == _currentEnemy )
ClearCurrentEnemy();
_hateList.RemoveObjectAt(i);
continue;
}
UpdateDistance( listIndex );
UpdateCanSee( listIndex );
// Bump the player's action level, TODO: this needs to change to a general you have been targeted call sometime
if ( listIndex->enemy && listIndex->enemy->isSubclassOf( Player ) )
{
if ( act->GetActorFlag(ACTOR_FLAG_UPDATE_ACTION_LEVEL) )
{
Player *player = (Player *)(Entity *)listIndex->enemy;
player->IncreaseActionLevel( 100 );
}
}
if ( act->GetActorFlag(ACTOR_FLAG_UPDATE_HATE_WITH_ATTACKERS) )
UpdateAttackers( listIndex );
/*if ( !act->combatSubsystem->CanAttackTarget( listIndex->enemy ) )
{
listIndex->hate = 0.0f;
if ( listIndex->enemy == _currentEnemy )
ClearCurrentEnemy();
_hateList.RemoveObjectAt(i);
}
*/
//If we haven't seen
if (
( act->timeBetweenSleepChecks > 0.0f ) &&
( listIndex->lastSightTime + act->timeBetweenSleepChecks <= level.time && !gi.inPVS( listIndex->enemy->centroid, act->centroid ) )
)
{
if ( listIndex->enemy == _currentEnemy && !_lockedOnCurrentEnemy )
ClearCurrentEnemy();
_hateList.RemoveObjectAt(i);
}
}
// Try and go back to sleep
TrySleep();
//If we don't have an enemy, tell our senses to keep looking
act->sensoryPerception->SenseEnemies();
if ( GetCurrentEnemy() || act->GetActorFlag( ACTOR_FLAG_INVESTIGATING ) || ( act->mode == ACTOR_MODE_SCRIPT ) || ( act->mode == ACTOR_MODE_TALK ) )
act->last_time_active = level.time;
// Take care of enemies
act->strategos->Evaluate();
}
//
// Name: UpdateDistance
// Parameters: HateListEntry_t -- The List Entry to update
// Description: Updates the distance of the enemy
//
void EnemyManager::UpdateDistance( HateListEntry_t *listIndex )
{
Vector distance;
//float distanceLength;
if ( !listIndex || !listIndex->enemy )
return;
Vector enemyDistance;
enemyDistance = listIndex->enemy->origin;
distance = enemyDistance - act->origin;
//distanceLength = distance.length();
listIndex->lastDistance = distance.length();
}
void EnemyManager::UpdateAttackers( HateListEntry_t *listIndex )
{
if ( _currentEnemy == listIndex->enemy )
return;
int numberOfAttackers;
ActorGroup* group;
group = (ActorGroup*)groupcoordinator->GetGroup( act->GetGroupID() );
if ( !group )
return;
numberOfAttackers = group->CountMembersAttackingEnemy( listIndex->enemy );
listIndex->hate = listIndex->hate / (numberOfAttackers + 1);
}
//
// Name: UpdateCanSee
// Parameters: HateListEntry_t -- The List Entry to update
// Description: Updates the cansee of the enemy
//
void EnemyManager::UpdateCanSee( HateListEntry_t *listIndex )
{
if ( !listIndex || ( listIndex->nextSightTime > level.time ) )
return;
qboolean canSee;
canSee = act->sensoryPerception->CanSeeEntity( act , listIndex->enemy , true , true );
// Notify Strategos of status change
if ( canSee != listIndex->canSee )
act->strategos->NotifySightStatusChanged( listIndex->enemy , canSee );
// Update the SightCheckTimes
listIndex->canSee = canSee;
// We use a faster delay for our current enemy than everyone else
float next_sight_delay;
if ( listIndex->enemy == _currentEnemy )
next_sight_delay = act->max_inactive_time / 5.0f + G_CRandom( 0.5f );
else
next_sight_delay = MIN_SIGHT_DELAY + ( act->max_inactive_time / 2.0f + G_CRandom( 0.5f ) );
if ( next_sight_delay < 1.0f )
next_sight_delay = 1.0f;
listIndex->nextSightTime = level.time + next_sight_delay;
if ( canSee )
listIndex->lastSightTime = level.time;
if ( listIndex->lastSightTime + act->max_inactive_time < level.time )
ClearCurrentEnemy();
}
//
// Name: LockOnCurrentEnemy
// Parameters: qboolean lock
// Description: Sets the _lockedOnCurrentEnemy flag
//
void EnemyManager::LockOnCurrentEnemy( qboolean lock )
{
_lockedOnCurrentEnemy = lock;
}
//
// Name: IsLockedOnCurrentEnemy
// Parameters: None
// Description: Returns the _lockedOnCurrentEnemy flag
//
qboolean EnemyManager::IsLockedOnCurrentEnemy()
{
return _lockedOnCurrentEnemy;
}
Vector EnemyManager::GetAwayFromEnemies()
{
EntityPtr enemy;
HateListEntry_t listIndex;
Vector enemyToSelf;
Vector temp;
float mag;
Vector bestAwayVector;
for ( int i = 1 ; i <= _hateList.NumObjects() ; i++ )
{
listIndex = _hateList.ObjectAt( i );
enemy = listIndex.enemy;
enemyToSelf = act->origin - enemy->origin;
mag = enemyToSelf.lengthSquared();
temp = enemyToSelf * (1 / mag);
bestAwayVector = bestAwayVector + temp;
}
bestAwayVector.normalize();
return bestAwayVector;
}
qboolean EnemyManager::InEnemyLineOfFire()
{
Actor *enemyActor = NULL;
Player *enemyPlayer = NULL;
Vector enemyToSelf;
float angleDiff = 0.0f;
if ( !_currentEnemy )
return false;
enemyToSelf = act->origin - _currentEnemy->origin;
enemyToSelf = enemyToSelf.toAngles();
if ( _currentEnemy->isSubclassOf(Actor) )
{
enemyActor = (Actor*)(Entity*)_currentEnemy;
if ( !enemyActor )
return false;
angleDiff = abs( (int) AngleNormalize180(enemyActor->angles[YAW] - enemyToSelf[YAW]) );
}
if ( _currentEnemy->isSubclassOf(Player) )
{
enemyPlayer = (Player*)(Entity*)_currentEnemy;
if ( !enemyPlayer )
return false;
Vector pAngles = enemyPlayer->GetVAngles();
angleDiff = abs( (int) AngleNormalize180(pAngles[YAW] - enemyToSelf[YAW]) );
}
if ( angleDiff < 10.0f )
return true;
return false;
}
float EnemyManager::GetDistanceFromEnemy()
{
Vector selfToEnemy;
if ( !_currentEnemy )
return -1;
selfToEnemy = _currentEnemy->origin - act->origin;
return selfToEnemy.length();
}
//
// Name: DoArchive
// Parameters: Archiver &arc -- The archiver object
// Actor *actor -- The actor
// Description: Sets the act pointer and calls Archive
//
void EnemyManager::DoArchive( Archiver &arc , Actor *actor )
{
Archive( arc );
if ( actor )
act = actor;
else
gi.Error( ERR_FATAL, "EnemyManager::DoArchive -- actor is NULL" );
}
//
// Name: Archive()
// Parameters: Archiver &arc -- The archiver object
// Description: Archives the class
//
void EnemyManager::Archive ( Archiver &arc )
{
HateListEntry_t hateEntry;
HateListEntry_t *realHateEntry;
int numEntries;
if ( arc.Saving() )
{
numEntries = _hateList.NumObjects();
arc.ArchiveInteger( &numEntries );
for ( int i = 1 ; i <= numEntries ; i++ )
{
hateEntry = _hateList.ObjectAt( i );
arc.ArchiveSafePointer( &hateEntry.enemy );
arc.ArchiveFloat( &hateEntry.lastSightTime );
arc.ArchiveFloat( &hateEntry.nextSightTime );
arc.ArchiveBoolean( &hateEntry.canSee );
arc.ArchiveFloat( &hateEntry.damageCaused );
arc.ArchiveFloat( &hateEntry.hate );
arc.ArchiveFloat( &hateEntry.lastDistance );
}
}
else
{
arc.ArchiveInteger( &numEntries );
_hateList.Resize( numEntries );
for ( int i = 1 ; i <= numEntries ; i++ )
{
_hateList.AddObject( hateEntry );
realHateEntry = &_hateList.ObjectAt( i );
arc.ArchiveSafePointer( &realHateEntry->enemy );
arc.ArchiveFloat( &realHateEntry->lastSightTime );
arc.ArchiveFloat( &realHateEntry->nextSightTime );
arc.ArchiveBoolean( &realHateEntry->canSee );
arc.ArchiveFloat( &realHateEntry->damageCaused );
arc.ArchiveFloat( &realHateEntry->hate );
arc.ArchiveFloat( &realHateEntry->lastDistance );
}
}
arc.ArchiveSafePointer( &_currentEnemy );
arc.ArchiveSafePointer( &_lastEnemy );
arc.ArchiveSafePointer( &_alternateTarget );
arc.ArchiveBoolean( &_lockedOnCurrentEnemy );
arc.ArchiveFloat( &_currentEnemyHate );
}
//----------------------------------------------------------------
// Name: TrySleep
// Class: EnemyManager
//
// Description: Puts the actor to sleep if it can
//
// Parameters:
// None
//
// Returns: None
//----------------------------------------------------------------
void EnemyManager::TrySleep( void )
{
const Entity *currentEnemy = GetCurrentEnemy();
// This is here because, if the ai gets turned off in the level, we don't want to go to sleep for if/when
// the ai gets turned back on in the level
if ( !level.ai_on )
act->last_time_active = level.time;
// See if we should go back to sleep -- If max_inactive_time < 1 , then the actor will never go to sleep
// If we DO have a max_inactive_time > 0 AND our last_time_active == 0 ( meaning it's our first time in here ) we
// should go ahead and try to fall asleep even though we have hit our max_inactive_time
if ( !currentEnemy && ( act->max_inactive_time > 0.0f ) && ( (act->last_time_active + act->max_inactive_time < level.time)))
{
//Well, we haven't had an enemy for a while, so let's see if the player is nearby
Player *player = 0;
for(int i = 0; i < game.maxclients; i++)
{
player = GetPlayer(i);
if ( player )
{
//We should NOT fall asleep if:
// our mode is ACTOR_MODE_IDLE _AND_ player flags are not equal to FL_NOTARGET
// OR
// Player is within our vision distance
// OR
// Player is within the PVS
//
// 7/15/02 -- SK
// Added via && the "gi.inPVS( player->centroid, act->centroid )" to the ACTOR_MODE_IDLE
// checks because, without it, all AI_OFF'd actors would still be considered "active"
// and this was ruining the framerate... I do not believe this is going to have any
// detrimental side effects.
//
if ( ( act->mode == ACTOR_MODE_IDLE ) && !(player->flags & FL_NOTARGET) && gi.inPVS( player->centroid, act->centroid ) || act->sensoryPerception->WithinVisionDistance(player) || gi.inPVS( player->centroid, act->centroid ) )
{
act->last_time_active = level.time;
}
else
{
if ( act->mode == ACTOR_MODE_AI )
{
act->EndMode();
act->Sleep();
if ( act->idle_thread.length() > 1 )
{
ExecuteThread( act->idle_thread, false );
}
}
else
{
act->Sleep();
}
}
}
}
}
}
bool EnemyManager::IsAnyEnemyInRange( float range )
{
HateListEntry_t *listIndex;
for ( int i = _hateList.NumObjects() ; i > 0 ; i-- )
{
listIndex = &_hateList.ObjectAt( i );
//Check if enemy is alive
if ( !act->IsEntityAlive( listIndex->enemy ) )
{
if ( listIndex->enemy == _currentEnemy )
ClearCurrentEnemy();
_hateList.RemoveObjectAt(i);
continue;
}
if ( act->WithinDistance( listIndex->enemy , range ) )
return true;
}
return false;
}
float EnemyManager::getEnemyCount()
{
return _hateList.NumObjects();
}
bool EnemyManager::CanGetToEntity(Entity *ent)
{
FindMovementPath find;
Path *path;
bool success;
success = false;
// Set up our pathing heuristics
find.heuristic.self = act;
find.heuristic.setSize( act->size );
find.heuristic.entnum = act->entnum;
path = find.FindPath( act->origin, ent->origin );
if ( path )
{
success = true;
}
delete path;
path = NULL;
return success;
}
bool EnemyManager::HasEnemy()
{
if ( _currentEnemy )
return true;
return false;
}