mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-20 04:30:12 +02:00
Quake 4 integrated with DoomRTX
This commit is contained in:
@@ -0,0 +1,767 @@
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "../Game_local.h"
|
||||
#include "AI.h"
|
||||
#include "AI_Manager.h"
|
||||
|
||||
idVec4 aiTeamColor[AITEAM_NUM] = { idVec4 ( 0.0f, 1.0f, 0.0f, 1.0f ),
|
||||
idVec4 ( 1.0f, 0.0f, 0.0f, 1.0f ) };
|
||||
|
||||
rvAIManager aiManager;
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::rvAIManager
|
||||
================
|
||||
*/
|
||||
rvAIManager::rvAIManager ( void ) {
|
||||
Clear();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::IsActive
|
||||
================
|
||||
*/
|
||||
bool rvAIManager::IsActive( void ){
|
||||
if( gameLocal.isMultiplayer ){
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::RunFrame
|
||||
================
|
||||
*/
|
||||
void rvAIManager::RunFrame ( void ){
|
||||
if ( !IsActive() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Pop the top simple think off the list
|
||||
if ( !simpleThink.IsListEmpty() ) {
|
||||
simpleThink.Next()->simpleThinkNode.Remove ( );
|
||||
}
|
||||
|
||||
// Display current ai speeds
|
||||
if ( ai_speeds.GetBool ( ) && thinkCount > 0 ) {
|
||||
gameLocal.Printf ( "ai:%6i n:%2i s:%2i all:%5.2f t:%5.2f e:%5.2f m:%5.f\n",
|
||||
gameLocal.framenum, thinkCount, simpleThinkCount,
|
||||
timerThink.Milliseconds(),
|
||||
timerTactical.Milliseconds(),
|
||||
timerFindEnemy.Milliseconds(),
|
||||
timerMove.Milliseconds() );
|
||||
}
|
||||
|
||||
// RAVEN BEGIN
|
||||
// cdr: Alternate Routes Bug
|
||||
int i;
|
||||
int j;
|
||||
// look for reaches that are no longer blocked
|
||||
for ( i=0; i<blockedReaches.Num(); i++ ) {
|
||||
aiBlocked_t& b = blockedReaches[i];
|
||||
|
||||
// check all blockers for changes in position
|
||||
for ( j=0; j<b.blockers.Num(); j++ ) {
|
||||
if (gameLocal.GetTime()>b.time) {
|
||||
break;
|
||||
}
|
||||
|
||||
idEntityPtr<idEntity> blockent = b.blockers[j];
|
||||
if (!blockent.IsValid() || blockent->DistanceTo(b.positions[j])>10.0f) {
|
||||
break;
|
||||
}
|
||||
if (blockent->IsType(idAI::GetClassType())) {
|
||||
idAI* blockentAI = static_cast<idAI*>(blockent.GetEntity());
|
||||
if (blockentAI->move.moveDest.Dist2XY(b.positions[j])>100.0f) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if any one of the blockers moved or no longer exists, re-enable this reach
|
||||
if ( !b.blockers.Num() || j<b.blockers.Num() ) {
|
||||
b.aas->SetReachabilityState(b.reach, true);
|
||||
blockedReaches.RemoveIndex(i);
|
||||
break;
|
||||
}
|
||||
|
||||
// DEBUG GRAPHICS
|
||||
if ( ai_debugMove.GetBool() ) {
|
||||
gameRenderWorld->DebugLine( colorRed, b.reach->start, b.reach->start + idVec3(0,0,40.0f), gameLocal.msec );
|
||||
for ( j=0; j<b.blockers.Num(); j++ ) {
|
||||
if (b.blockers[j].IsValid()) {
|
||||
gameRenderWorld->DebugArrow( colorRed, b.blockers[j]->GetPhysics()->GetOrigin(), b.reach->start, 8, gameLocal.msec );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// RAVEN END
|
||||
|
||||
timerThink.Clear ( );
|
||||
timerTactical.Clear ( );
|
||||
timerFindEnemy.Clear ( );
|
||||
timerMove.Clear ( );
|
||||
|
||||
gameDebug.SetStatInt( "ai_thinkCount", thinkCount );
|
||||
|
||||
thinkCount = 0;
|
||||
simpleThinkCount = 0;
|
||||
|
||||
// Draw any debugging information
|
||||
DebugDraw ( );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::Clear
|
||||
================
|
||||
*/
|
||||
void rvAIManager::Clear( void ) {
|
||||
thinkCount = 0;
|
||||
simpleThinkCount = 0;
|
||||
timerThink.Clear ( );
|
||||
timerFindEnemy.Clear ( );
|
||||
timerTactical.Clear ( );
|
||||
timerMove.Clear ( );
|
||||
|
||||
blockedReaches.Clear ( );
|
||||
helpers.Clear ( );
|
||||
simpleThink.Clear ( );
|
||||
avoids.Clear ( );
|
||||
|
||||
memset ( &teamTimers, 0, sizeof(teamTimers) );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::UnMarkAllReachBlocked
|
||||
================
|
||||
*/
|
||||
void rvAIManager::UnMarkAllReachBlocked( void )
|
||||
{
|
||||
for ( int i=0; i<blockedReaches.Num(); i++ ) {
|
||||
blockedReaches[i].aas->SetReachabilityState(blockedReaches[i].reach, true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::ReMarkAllReachBlocked
|
||||
================
|
||||
*/
|
||||
void rvAIManager::ReMarkAllReachBlocked( void )
|
||||
{
|
||||
for ( int i=0; i<blockedReaches.Num(); i++ ) {
|
||||
blockedReaches[i].aas->SetReachabilityState(blockedReaches[i].reach, false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::MarkReachBlocked
|
||||
================
|
||||
*/
|
||||
void rvAIManager::MarkReachBlocked(idAAS* aas, idReachability* reach, const idList<idEntity*>& blockers) {
|
||||
|
||||
// only if not already blocked
|
||||
if (!(reach->travelType&TFL_INVALID)) {
|
||||
aiBlocked_t blocked;
|
||||
blocked.aas = aas;
|
||||
blocked.reach = reach;
|
||||
blocked.time = gameLocal.GetTime() + 5000.0f;
|
||||
|
||||
for (int i=0; i<blockers.Num(); i++) {
|
||||
if (blockers[i] && blockers[i]->GetPhysics() && (blockers[i]->GetPhysics()->IsAtRest() || blockers[i]->GetPhysics()->GetLinearVelocity().LengthSqr()<2500.0f)) {
|
||||
blocked.blockers.Append(blockers[i]);
|
||||
blocked.positions.Append(blockers[i]->GetPhysics()->GetOrigin());
|
||||
}
|
||||
}
|
||||
if (blocked.blockers.Num()) {
|
||||
aas->SetReachabilityState(reach, false);
|
||||
blockedReaches.Append(blocked);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::ReactToPlayerAttack
|
||||
================
|
||||
*/
|
||||
void rvAIManager::ReactToPlayerAttack ( idPlayer* player, const idVec3 &origin, const idVec3 &dir ){
|
||||
idActor* actor;
|
||||
float expandSize;
|
||||
|
||||
// Check all enemies and see if they need to react
|
||||
for ( actor = GetEnemyTeam ( (aiTeam_t)player->team ); actor; actor = actor->teamNode.Next() ) {
|
||||
// Skip non ai entities
|
||||
if ( !actor->IsType ( idAI::Type ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
idAI *curAI = static_cast<idAI*>(actor);
|
||||
|
||||
// See if it will pass through an expanded bounding box
|
||||
expandSize = curAI->spawnArgs.GetFloat( "shotAtReactionRange", "16" );
|
||||
if ( !curAI->GetPhysics()->GetAbsBounds ( ).Expand(expandSize).LineIntersection ( origin, origin + dir * curAI->combat.visRange ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
curAI->ReactToShotAt ( player, origin, dir );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::Save
|
||||
================
|
||||
*/
|
||||
void rvAIManager::Save( idSaveGame *savefile ) const {
|
||||
int i;
|
||||
int j;
|
||||
|
||||
// Write out team list
|
||||
for ( i = 0; i < AITEAM_NUM; i ++ ) {
|
||||
idActor* actor;
|
||||
savefile->WriteInt( teams[i].Num() );
|
||||
for( actor = teams[i].Next(); actor != NULL; actor = actor->teamNode.Next() ) {
|
||||
savefile->WriteObject( actor );
|
||||
}
|
||||
}
|
||||
|
||||
// Write out team timers
|
||||
for ( i = 0; i < AITEAM_NUM; i ++ ) {
|
||||
for ( j = 0; j < AITEAMTIMER_MAX; j ++ ) {
|
||||
savefile->WriteInt ( teamTimers[i][j] );
|
||||
}
|
||||
}
|
||||
|
||||
// Write out team timers
|
||||
savefile->WriteInt ( avoids.Num ( ) );
|
||||
for ( i = 0; i < avoids.Num ( ); i ++ ) {
|
||||
savefile->WriteVec3 ( avoids[i].origin );
|
||||
savefile->WriteFloat ( avoids[i].radius );
|
||||
savefile->WriteInt ( avoids[i].team );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::Restore
|
||||
================
|
||||
*/
|
||||
void rvAIManager::Restore( idRestoreGame *savefile ){
|
||||
int i;
|
||||
int j;
|
||||
|
||||
Clear ( );
|
||||
|
||||
// Write out team list
|
||||
for ( i = 0; i < AITEAM_NUM; i ++ ) {
|
||||
idActor* actor;
|
||||
savefile->ReadInt( j );
|
||||
for ( ; j > 0; j -- ) {
|
||||
savefile->ReadObject ( reinterpret_cast<idClass *&>( actor ) );
|
||||
if ( actor ) {
|
||||
actor->teamNode.AddToEnd ( teams[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read team timers
|
||||
memset ( teamTimers, 0, sizeof(teamTimers) );
|
||||
for ( i = 0; i < AITEAM_NUM; i ++ ) {
|
||||
for ( j = 0; j < AITEAMTIMER_MAX; j ++ ) {
|
||||
savefile->ReadInt ( teamTimers[i][j] );
|
||||
}
|
||||
}
|
||||
|
||||
// Read in team timers
|
||||
savefile->ReadInt ( j );
|
||||
avoids.SetNum ( j );
|
||||
for ( i = 0; i < j; i ++ ) {
|
||||
savefile->ReadVec3 ( avoids[i].origin );
|
||||
savefile->ReadFloat ( avoids[i].radius );
|
||||
savefile->ReadInt ( avoids[i].team );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvAIManager::AddTeammate
|
||||
=====================
|
||||
*/
|
||||
void rvAIManager::AddTeammate ( idActor* actor ) {
|
||||
// If its already in a team least then ignore the call.
|
||||
// NOTE: You have to call removeteammate before addteammate to switch the
|
||||
// actor from one team to another
|
||||
if ( actor->teamNode.InList ( ) ) {
|
||||
return;
|
||||
}
|
||||
actor->teamNode.AddToEnd ( teams[actor->team] );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvAIManager::RemoveTeammate
|
||||
=====================
|
||||
*/
|
||||
void rvAIManager::RemoveTeammate ( idActor* actor ) {
|
||||
actor->teamNode.Remove ( );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvAIManager::IsSimpleThink
|
||||
|
||||
Determines whether or not the given AI entity should be simple thinking this frame
|
||||
=====================
|
||||
*/
|
||||
bool rvAIManager::IsSimpleThink ( idAI* ai ) {
|
||||
|
||||
// no simple think if simple thinking is disabled or we are the head node
|
||||
if ( ai_disableSimpleThink.GetBool() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add to simple think list
|
||||
if ( !ai->simpleThinkNode.InList ( ) ) {
|
||||
ai->simpleThinkNode.AddToEnd ( simpleThink );
|
||||
}
|
||||
|
||||
// If head of list then its a complex think
|
||||
if ( ai->simpleThinkNode.Prev() == NULL ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::GetEnemyTeam
|
||||
================
|
||||
*/
|
||||
idActor* rvAIManager::GetEnemyTeam ( aiTeam_t team ) {
|
||||
switch ( team ) {
|
||||
case AITEAM_MARINE:
|
||||
return teams[AITEAM_STROGG].Next();
|
||||
case AITEAM_STROGG:
|
||||
return teams[AITEAM_MARINE].Next();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::GetAllyTeam
|
||||
================
|
||||
*/
|
||||
idActor* rvAIManager::GetAllyTeam ( aiTeam_t team ) {
|
||||
switch ( team ) {
|
||||
case AITEAM_MARINE:
|
||||
return teams[AITEAM_MARINE].Next();
|
||||
case AITEAM_STROGG:
|
||||
return teams[AITEAM_STROGG].Next();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::ValidateDestination
|
||||
|
||||
Validate whether or not the destinations is a destination
|
||||
================
|
||||
*/
|
||||
bool rvAIManager::ValidateDestination ( idAI* ai, const idVec3& dest, bool skipCurrent, idActor* skipActor ) const {
|
||||
int i;
|
||||
idBounds bounds;
|
||||
idAI* ignore;
|
||||
|
||||
ignore = (!skipCurrent && ai && !ai->SkipCurrentDestination ( )) ? ai : NULL;
|
||||
|
||||
bounds = ai->GetPhysics()->GetBounds ( );
|
||||
bounds.TranslateSelf ( dest );
|
||||
bounds.ExpandSelf ( 16.0f );
|
||||
|
||||
// All teams and all actors on those teams
|
||||
for ( i = 0; i < AITEAM_NUM; i ++ ) {
|
||||
idActor* actor;
|
||||
for ( actor = teams[i].Next(); actor; actor = actor->teamNode.Next() ) {
|
||||
// Ignored?
|
||||
if ( actor == ignore || actor == skipActor || actor->IsHidden ( ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the actor is AI that is moving we should check their destination rather than where they are now
|
||||
if ( actor->IsType ( idAI::Type ) ) {
|
||||
idAI* aiactor = static_cast<idAI*>(actor);
|
||||
if ( aiactor->move.moveCommand >= NUM_NONMOVING_COMMANDS ) {
|
||||
if ( bounds.IntersectsBounds ( aiactor->GetPhysics()->GetBounds().Translate ( aiactor->move.moveDest ) ) ) {
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Does the destination overlap this actor?
|
||||
if ( bounds.IntersectsBounds ( actor->GetPhysics()->GetAbsBounds ( ) ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Destinations inside an avoid area are invalid
|
||||
for ( i = avoids.Num() - 1; i >= 0; i -- ) {
|
||||
const aiAvoid_t& avoid = avoids[i];
|
||||
// Skip all avoids that arent meant for this team
|
||||
if ( avoid.team != -1 && ai->team != avoid.team ) {
|
||||
continue;
|
||||
}
|
||||
// Skip if within range of the avoid
|
||||
if ( (avoid.origin - dest).LengthSqr ( ) < Square ( avoid.radius ) ) {
|
||||
if ( ai_debugMove.GetBool() || ai_debugTactical.GetBool() ) {
|
||||
gameRenderWorld->DebugCircle( colorRed, avoid.origin, idVec3(0,0,1), avoid.radius, 25 );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::NearestTeammateToPoint
|
||||
|
||||
Returns the teammate closest to the given point with the given parameters
|
||||
================
|
||||
*/
|
||||
idActor* rvAIManager::NearestTeammateToPoint ( idActor* from, idVec3 point, bool nonPlayer, float maxRange, bool checkFOV, bool checkLOS ) {
|
||||
idActor* actor = NULL;
|
||||
idActor* closestActor = NULL;
|
||||
float distSqr;
|
||||
float bestDistSqr;
|
||||
|
||||
closestActor = 0x0;
|
||||
bestDistSqr = Square ( maxRange );
|
||||
|
||||
// Iterate through all teammates
|
||||
for( actor = aiManager.GetAllyTeam ( (aiTeam_t)from->team ); actor; actor = actor->teamNode.Next() ) {
|
||||
//Hidden?
|
||||
if ( actor->fl.hidden ) {
|
||||
continue;
|
||||
}
|
||||
//Self?
|
||||
if ( actor == from ) {
|
||||
continue;
|
||||
}
|
||||
//Player?
|
||||
if ( nonPlayer && actor->IsType( idPlayer::GetClassType() ) ) {
|
||||
continue;
|
||||
}
|
||||
//Dead?
|
||||
if ( actor->health <= 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//Calc Range and check to see if closer before doing any complicated checks
|
||||
distSqr = (point - actor->GetPhysics()->GetOrigin()).LengthSqr();
|
||||
if ( distSqr >= bestDistSqr ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//point in actor's in FOV?
|
||||
if ( checkFOV && !actor->CheckFOV( point ) ) {
|
||||
continue;
|
||||
}
|
||||
//actor has clear LOS to point?
|
||||
if ( checkLOS && !actor->CanSeeFrom ( from->GetEyePosition ( ), point, false ) ) {
|
||||
continue;
|
||||
}
|
||||
// New best actor
|
||||
bestDistSqr = distSqr;
|
||||
closestActor = actor;
|
||||
}
|
||||
return closestActor;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::NearestTeammateEnemy
|
||||
|
||||
Returns the closest enemy of an ally.
|
||||
================
|
||||
*/
|
||||
idEntity* rvAIManager::NearestTeammateEnemy( idActor* from, float maxRange, bool checkFOV, bool checkLOS, idActor** closestAllyWithEnemy ) {
|
||||
idActor* actor;
|
||||
idAI* allyAI;
|
||||
idEntity* allyEnemy;
|
||||
idEntity* closestAllyEnemy;
|
||||
float distSqr;
|
||||
float bestDistSqr;
|
||||
|
||||
bestDistSqr = Square ( maxRange );
|
||||
closestAllyEnemy = NULL;
|
||||
|
||||
// Optionally return the ally whos enemy it is
|
||||
if ( closestAllyWithEnemy ) {
|
||||
*closestAllyWithEnemy = NULL;
|
||||
}
|
||||
|
||||
for( actor = aiManager.GetAllyTeam ( (aiTeam_t)from->team ); actor; actor = actor->teamNode.Next() ) {
|
||||
//Hidden?
|
||||
if ( actor->fl.hidden ) {
|
||||
continue;
|
||||
}
|
||||
//Self?
|
||||
if ( actor == from ) {
|
||||
continue;
|
||||
}
|
||||
//Dead?
|
||||
if ( actor->health <= 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
allyAI = dynamic_cast<idAI*>(actor);
|
||||
if ( !allyAI ) {
|
||||
//player?
|
||||
allyEnemy = actor->EnemyWithMostHealth();
|
||||
if ( !allyEnemy ) {
|
||||
continue;
|
||||
}
|
||||
if ( allyEnemy->health <= 0 ) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
allyEnemy = allyAI->GetEnemy();
|
||||
//has enemy?
|
||||
if ( !allyEnemy ) {
|
||||
continue;
|
||||
}
|
||||
//still alive?
|
||||
if ( allyAI->enemy.fl.dead ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//Calc Range and check to see if closer before doing any complicated checks
|
||||
distSqr = (actor->GetPhysics()->GetOrigin() - from->GetPhysics()->GetOrigin()).LengthSqr ( );
|
||||
if ( distSqr >= bestDistSqr ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//point in actor's in FOV?
|
||||
if ( checkFOV ) {
|
||||
if ( !from->CheckFOV( actor->GetPhysics()->GetOrigin() ) ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
//actor has clear LOS to point?
|
||||
if ( checkLOS ) {
|
||||
if ( !from->CanSee( actor, false ) ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
bestDistSqr = distSqr;
|
||||
closestAllyEnemy = allyEnemy;
|
||||
|
||||
if ( closestAllyWithEnemy ) {
|
||||
*closestAllyWithEnemy = actor;
|
||||
}
|
||||
}
|
||||
return closestAllyEnemy;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::LocalTeamHasEnemies
|
||||
|
||||
Returns true if nearby members of my team have any enemies or if any nearby enemies have enemies that are nearby members of my team
|
||||
================
|
||||
*/
|
||||
bool rvAIManager::LocalTeamHasEnemies ( idAI* self, float maxBuddyRange, float maxEnemyRange, bool checkPVS ) {
|
||||
idActor* actor = NULL;
|
||||
pvsHandle_t pvs;
|
||||
|
||||
if ( !self ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Iterate through all teammates
|
||||
for( actor = aiManager.GetAllyTeam ( (aiTeam_t)self->team ); actor; actor = actor->teamNode.Next() ) {
|
||||
//Hidden?
|
||||
if ( actor->fl.hidden ) {
|
||||
continue;
|
||||
}
|
||||
//Dead?
|
||||
if ( actor->health <= 0 ) {
|
||||
continue;
|
||||
}
|
||||
if ( actor->IsType( idAI::GetClassType() ) ) {
|
||||
//Has an enemy?
|
||||
if ( !((idAI*)actor)->GetEnemy() ) {
|
||||
continue;
|
||||
}
|
||||
//Has an enemy
|
||||
if ( checkPVS ) {
|
||||
// Setup our local variables used in the search
|
||||
pvs = gameLocal.pvs.SetupCurrentPVS( actor->GetPVSAreas(), actor->GetNumPVSAreas() );
|
||||
// If this enemy isnt in the same pvps then use them as a backup
|
||||
if ( pvs.i > 0
|
||||
&& pvs.i < MAX_CURRENT_PVS
|
||||
&& !gameLocal.pvs.InCurrentPVS( pvs, ((idAI*)actor)->GetEnemy()->GetPVSAreas(), ((idAI*)actor)->GetEnemy()->GetNumPVSAreas() ) ) {
|
||||
gameLocal.pvs.FreeCurrentPVS( pvs );
|
||||
continue;
|
||||
}
|
||||
gameLocal.pvs.FreeCurrentPVS( pvs );
|
||||
}
|
||||
|
||||
}
|
||||
//close enough?
|
||||
if ( actor != self && self->DistanceTo( actor->GetPhysics()->GetOrigin() ) > maxBuddyRange ) {
|
||||
continue;
|
||||
}
|
||||
//Anyone mad at him?
|
||||
if ( !actor->ClosestEnemyToPoint( actor->GetPhysics()->GetOrigin(), maxEnemyRange, true, checkPVS ) ) {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::ActorIsBehindActor
|
||||
|
||||
Returns true if the given 'ambuser' is behind the given 'victim'
|
||||
================
|
||||
*/
|
||||
bool rvAIManager::ActorIsBehindActor( idActor* ambusher, idActor* victim ) {
|
||||
idVec3 dir2Ambusher = ambusher->GetPhysics()->GetOrigin() - victim->GetPhysics()->GetOrigin();
|
||||
float dist = dir2Ambusher.Normalize();
|
||||
if ( DotProduct(dir2Ambusher, victim->viewAxis[0] ) < 0 && dist < 200.0f ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
rvAIManager - Helpers
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvAIManager::RegisterHelper
|
||||
=====================
|
||||
*/
|
||||
void rvAIManager::RegisterHelper ( rvAIHelper* helper ) {
|
||||
helper->helperNode.AddToEnd ( helpers );
|
||||
UpdateHelpers ( );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvAIManager::UnregisterHelper
|
||||
=====================
|
||||
*/
|
||||
void rvAIManager::UnregisterHelper ( rvAIHelper* helper ) {
|
||||
helper->helperNode.Remove ( );
|
||||
UpdateHelpers ( );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
rvAIManager::FindClosestHelper
|
||||
=====================
|
||||
*/
|
||||
rvAIHelper* rvAIManager::FindClosestHelper ( const idVec3& origin ) {
|
||||
rvAIHelper* helper;
|
||||
rvAIHelper* bestHelper;
|
||||
float bestDist;
|
||||
float dist;
|
||||
|
||||
bestDist = idMath::INFINITY;
|
||||
bestHelper = NULL;
|
||||
for ( helper = helpers.Next(); helper; helper = helper->helperNode.Next( ) ) {
|
||||
dist = (origin - helper->GetPhysics()->GetOrigin()).LengthFast ( );
|
||||
if ( dist < bestDist ) {
|
||||
bestDist = dist;
|
||||
bestHelper = helper;
|
||||
}
|
||||
}
|
||||
return bestHelper;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::UpdateHelpers
|
||||
================
|
||||
*/
|
||||
void rvAIManager::UpdateHelpers ( void ) {
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < AITEAM_NUM; i ++ ) {
|
||||
idActor* actor;
|
||||
for ( actor = teams[i].Next(); actor; actor = actor->teamNode.Next() ) {
|
||||
if ( actor->IsHidden ( ) || !actor->IsType ( idAI::Type ) ) {
|
||||
continue;
|
||||
}
|
||||
static_cast<idAI*>(actor)->UpdateHelper ( );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
rvAIManager - Debugging
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::DebugDraw
|
||||
================
|
||||
*/
|
||||
void rvAIManager::DebugDraw ( void ) {
|
||||
// Draw helpers?
|
||||
if ( ai_debugHelpers.GetBool ( ) ) {
|
||||
DebugDrawHelpers ( );
|
||||
|
||||
int i;
|
||||
for ( i = 0; i < avoids.Num(); i ++ ) {
|
||||
const aiAvoid_t& avoid = avoids[i];
|
||||
gameRenderWorld->DebugCircle ( colorOrange, avoid.origin, idVec3(0,0,1), avoid.radius, 10, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvAIManager::DebugDrawHelpers
|
||||
================
|
||||
*/
|
||||
void rvAIManager::DebugDrawHelpers ( void ) {
|
||||
rvAIHelper* helper;
|
||||
for ( helper = helpers.Next(); helper; helper = helper->helperNode.Next( ) ) {
|
||||
helper->DrawDebugEntityInfo ( );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user