codemp/game/NPC_senses.c File Reference

#include "b_local.h"

Go to the source code of this file.

Defines

#define MAX_INTEREST_DIST   ( 256 * 256 )

Functions

qboolean G_ClearLineOfSight (const vec3_t point1, const vec3_t point2, int ignore, int clipmask)
qboolean CanSee (gentity_t *ent)
qboolean InFront (vec3_t spot, vec3_t from, vec3_t fromAngles, float threshHold)
qboolean InFOV3 (vec3_t spot, vec3_t from, vec3_t fromAngles, int hFOV, int vFOV)
qboolean InFOV2 (vec3_t origin, gentity_t *from, int hFOV, int vFOV)
qboolean InFOV (gentity_t *ent, gentity_t *from, int hFOV, int vFOV)
qboolean InVisrange (gentity_t *ent)
visibility_t NPC_CheckVisibility (gentity_t *ent, int flags)
float G_GetLightLevel (vec3_t pos, vec3_t fromDir)
int G_CheckAlertEvents (gentity_t *self, qboolean checkSight, qboolean checkSound, float maxSeeDist, float maxHearDist, int ignoreAlert, qboolean mustHaveOwner, int minAlertLevel)
int NPC_CheckAlertEvents (qboolean checkSight, qboolean checkSound, int ignoreAlert, qboolean mustHaveOwner, int minAlertLevel)
qboolean G_CheckForDanger (gentity_t *self, int alertEvent)
qboolean NPC_CheckForDanger (int alertEvent)
qboolean RemoveOldestAlert (void)
void AddSoundEvent (gentity_t *owner, vec3_t position, float radius, alertEventLevel_e alertLevel, qboolean needLOS)
void AddSightEvent (gentity_t *owner, vec3_t position, float radius, alertEventLevel_e alertLevel, float addLight)
void ClearPlayerAlertEvents (void)
qboolean G_ClearLOS (gentity_t *self, const vec3_t start, const vec3_t end)
qboolean G_ClearLOS2 (gentity_t *self, gentity_t *ent, const vec3_t end)
qboolean G_ClearLOS3 (gentity_t *self, const vec3_t start, gentity_t *ent)
qboolean G_ClearLOS4 (gentity_t *self, gentity_t *ent)
qboolean G_ClearLOS5 (gentity_t *self, const vec3_t end)
float NPC_GetHFOVPercentage (vec3_t spot, vec3_t from, vec3_t facing, float hFOV)
float NPC_GetVFOVPercentage (vec3_t spot, vec3_t from, vec3_t facing, float vFOV)
int G_FindLocalInterestPoint (gentity_t *self)
void SP_target_interest (gentity_t *self)

Variables

int eventClearTime


Define Documentation

#define MAX_INTEREST_DIST   ( 256 * 256 )
 

Definition at line 864 of file NPC_senses.c.

Referenced by G_FindLocalInterestPoint().


Function Documentation

void AddSightEvent gentity_t owner,
vec3_t  position,
float  radius,
alertEventLevel_e  alertLevel,
float  addLight
 

Definition at line 623 of file NPC_senses.c.

References AEL_DANGER, AET_SIGHT, level_locals_t::alertEvents, level_locals_t::curAlertID, gentity_t, level, MAX_ALERT_EVENTS, NULL, level_locals_t::numAlertEvents, RemoveOldestAlert(), level_locals_t::time, vec3_t, and VectorCopy.

Referenced by CorpsePhysics(), ForceTelepathyCheckDirectNPCTarget(), and NPC_BSRancor_Default().

00624 {
00625         //FIXME: Handle this in another manner?
00626         if ( level.numAlertEvents >= MAX_ALERT_EVENTS )
00627         {
00628                 if ( !RemoveOldestAlert() )
00629                 {//how could that fail?
00630                         return;
00631                 }
00632         }
00633 
00634         if ( owner == NULL && alertLevel < AEL_DANGER ) //allows un-owned danger alerts
00635                 return;
00636 
00637         //FIXME: if owner is not a player or player ally, and there are no player allies present,
00638         //                      perhaps we don't need to store the alert... unless we want the player to
00639         //                      react to enemy alert events in some way?
00640 
00641         VectorCopy( position, level.alertEvents[ level.numAlertEvents ].position );
00642 
00643         level.alertEvents[ level.numAlertEvents ].radius        = radius;
00644         level.alertEvents[ level.numAlertEvents ].level         = alertLevel;
00645         level.alertEvents[ level.numAlertEvents ].type          = AET_SIGHT;
00646         level.alertEvents[ level.numAlertEvents ].owner         = owner;                
00647         level.alertEvents[ level.numAlertEvents ].addLight      = addLight;     //will get added to actual light at that point when it's checked
00648         level.alertEvents[ level.numAlertEvents ].ID            = level.curAlertID++;
00649         level.alertEvents[ level.numAlertEvents ].timestamp     = level.time;
00650 
00651         level.numAlertEvents++;
00652 }

void AddSoundEvent gentity_t owner,
vec3_t  position,
float  radius,
alertEventLevel_e  alertLevel,
qboolean  needLOS
 

Definition at line 579 of file NPC_senses.c.

References AEL_DANGER, AET_SOUND, level_locals_t::alertEvents, level_locals_t::curAlertID, gentity_t, level, MAX_ALERT_EVENTS, NULL, level_locals_t::numAlertEvents, RemoveOldestAlert(), level_locals_t::time, vec3_t, and VectorCopy.

Referenced by ForceTelepathyCheckDirectNPCTarget(), NPC_BSRancor_Default(), and Rancor_Smash().

00580 {
00581         //FIXME: Handle this in another manner?
00582         if ( level.numAlertEvents >= MAX_ALERT_EVENTS )
00583         {
00584                 if ( !RemoveOldestAlert() )
00585                 {//how could that fail?
00586                         return;
00587                 }
00588         }
00589         
00590         if ( owner == NULL && alertLevel < AEL_DANGER ) //allows un-owned danger alerts
00591                 return;
00592 
00593         //FIXME: if owner is not a player or player ally, and there are no player allies present,
00594         //                      perhaps we don't need to store the alert... unless we want the player to
00595         //                      react to enemy alert events in some way?
00596 
00597         VectorCopy( position, level.alertEvents[ level.numAlertEvents ].position );
00598 
00599         level.alertEvents[ level.numAlertEvents ].radius        = radius;
00600         level.alertEvents[ level.numAlertEvents ].level         = alertLevel;
00601         level.alertEvents[ level.numAlertEvents ].type          = AET_SOUND;
00602         level.alertEvents[ level.numAlertEvents ].owner         = owner;
00603         if ( needLOS )
00604         {//a very low-level sound, when check this sound event, check for LOS
00605                 level.alertEvents[ level.numAlertEvents ].addLight      = 1;    //will force an LOS trace on this sound
00606         }
00607         else
00608         {
00609                 level.alertEvents[ level.numAlertEvents ].addLight      = 0;    //will force an LOS trace on this sound
00610         }
00611         level.alertEvents[ level.numAlertEvents ].ID            = level.curAlertID++;
00612         level.alertEvents[ level.numAlertEvents ].timestamp     = level.time;
00613 
00614         level.numAlertEvents++;
00615 }

qboolean CanSee gentity_t ent  ) 
 

Definition at line 47 of file NPC_senses.c.

References CalcEntitySpot(), trace_t::fraction, gentity_t, MASK_OPAQUE, NPC, NULL, entityState_s::number, qboolean, qfalse, qtrue, gentity_s::s, ShotThroughGlass(), SPOT_HEAD, SPOT_HEAD_LEAN, SPOT_LEGS, SPOT_ORIGIN, trap_Trace(), and vec3_t.

Referenced by NPC_CheckVisibility().

00048 {
00049         trace_t         tr;
00050         vec3_t          eyes;
00051         vec3_t          spot;
00052 
00053         CalcEntitySpot( NPC, SPOT_HEAD_LEAN, eyes );
00054 
00055         CalcEntitySpot( ent, SPOT_ORIGIN, spot );
00056         trap_Trace ( &tr, eyes, NULL, NULL, spot, NPC->s.number, MASK_OPAQUE );
00057         ShotThroughGlass (&tr, ent, spot, MASK_OPAQUE);
00058         if ( tr.fraction == 1.0 ) 
00059         {
00060                 return qtrue;
00061         }
00062 
00063         CalcEntitySpot( ent, SPOT_HEAD, spot );
00064         trap_Trace ( &tr, eyes, NULL, NULL, spot, NPC->s.number, MASK_OPAQUE );
00065         ShotThroughGlass (&tr, ent, spot, MASK_OPAQUE);
00066         if ( tr.fraction == 1.0 ) 
00067         {
00068                 return qtrue;
00069         }
00070 
00071         CalcEntitySpot( ent, SPOT_LEGS, spot );
00072         trap_Trace ( &tr, eyes, NULL, NULL, spot, NPC->s.number, MASK_OPAQUE );
00073         ShotThroughGlass (&tr, ent, spot, MASK_OPAQUE);
00074         if ( tr.fraction == 1.0 ) 
00075         {
00076                 return qtrue;
00077         }
00078 
00079         return qfalse;
00080 }

void ClearPlayerAlertEvents void   ) 
 

Definition at line 660 of file NPC_senses.c.

References ALERT_CLEAR_TIME, alertEvent_t, level_locals_t::alertEvents, eventClearTime, level, MAX_ALERT_EVENTS, memmove(), memset(), level_locals_t::numAlertEvents, level_locals_t::time, and alertEvent_s::timestamp.

00661 {
00662         int curNumAlerts = level.numAlertEvents;
00663         int i;
00664         //loop through them all (max 32)
00665         for ( i = 0; i < curNumAlerts; i++ )
00666         {
00667                 //see if the event is old enough to delete
00668                 if ( level.alertEvents[i].timestamp && level.alertEvents[i].timestamp + ALERT_CLEAR_TIME < level.time )
00669                 {//this event has timed out
00670                         //drop the count
00671                         level.numAlertEvents--;
00672                         //shift the rest down
00673                         if ( level.numAlertEvents > 0 )
00674                         {//still have more in the array
00675                                 if ( (i+1) < MAX_ALERT_EVENTS )
00676                                 {
00677                                         memmove( &level.alertEvents[i], &level.alertEvents[i+1], sizeof(alertEvent_t)*(MAX_ALERT_EVENTS-(i+1) ) );
00678                                 }
00679                         }
00680                         else
00681                         {//just clear this one... or should we clear the whole array?
00682                                 memset( &level.alertEvents[i], 0, sizeof( alertEvent_t ) );
00683                         }
00684                 }
00685         }
00686         //make sure this never drops below zero... if it does, something very very bad happened
00687         assert( level.numAlertEvents >= 0 );
00688 
00689         if ( eventClearTime < level.time )
00690         {//this is just a 200ms debouncer so things that generate constant alerts (like corpses and missiles) add an alert every 200 ms
00691                 eventClearTime = level.time + ALERT_CLEAR_TIME;
00692         }
00693 }

int G_CheckAlertEvents gentity_t self,
qboolean  checkSight,
qboolean  checkSound,
float  maxSeeDist,
float  maxHearDist,
int  ignoreAlert,
qboolean  mustHaveOwner,
int  minAlertLevel
 

Definition at line 478 of file NPC_senses.c.

References alertEvent_s::addLight, level_locals_t::alertEvents, CalcEntitySpot(), g_entities, G_GetLightLevel(), gentity_t, gentity_s::health, gNPCstats_e::hfov, alertEvent_s::level, level, alertEvent_s::light, gentity_s::NPC, NULL, alertEvent_s::position, SPOT_HEAD_LEAN, gNPC_t::stats, vec3_t, VectorSubtract, and gNPCstats_e::vfov.

Referenced by NPC_CheckAlertEvents().

00479 {
00480         int bestSoundEvent = -1;
00481         int bestSightEvent = -1;
00482         int bestSoundAlert = -1;
00483         int bestSightAlert = -1;
00484 
00485         if ( &g_entities[0] == NULL || g_entities[0].health <= 0 )
00486         {
00487                 //player is dead
00488                 return -1;
00489         }
00490 
00491         //get sound event
00492         bestSoundEvent = G_CheckSoundEvents( self, maxHearDist, ignoreAlert, mustHaveOwner, minAlertLevel );
00493         //get sound event alert level
00494         if ( bestSoundEvent >= 0 )
00495         {
00496                 bestSoundAlert = level.alertEvents[bestSoundEvent].level;
00497         }
00498 
00499         //get sight event
00500         if ( self->NPC )
00501         {
00502                 bestSightEvent = G_CheckSightEvents( self, self->NPC->stats.hfov, self->NPC->stats.vfov, maxSeeDist, ignoreAlert, mustHaveOwner, minAlertLevel );
00503         }
00504         else
00505         {
00506                 bestSightEvent = G_CheckSightEvents( self, 80, 80, maxSeeDist, ignoreAlert, mustHaveOwner, minAlertLevel );//FIXME: look at cg_view to get more accurate numbers?
00507         }
00508         //get sight event alert level
00509         if ( bestSightEvent >= 0 )
00510         {
00511                 bestSightAlert = level.alertEvents[bestSightEvent].level;
00512         }
00513 
00514         //return the one that has a higher alert (or sound if equal)
00515         //FIXME:        This doesn't take the distance of the event into account
00516 
00517         if ( bestSightEvent >= 0 && bestSightAlert > bestSoundAlert )
00518         {//valid best sight event, more important than the sound event
00519                 //get the light level of the alert event for this checker
00520                 vec3_t  eyePoint, sightDir;
00521                 //get eye point
00522                 CalcEntitySpot( self, SPOT_HEAD_LEAN, eyePoint );
00523                 VectorSubtract( level.alertEvents[bestSightEvent].position, eyePoint, sightDir );
00524                 level.alertEvents[bestSightEvent].light = level.alertEvents[bestSightEvent].addLight + G_GetLightLevel( level.alertEvents[bestSightEvent].position, sightDir );
00525                 //return the sight event
00526                 return bestSightEvent;
00527         }
00528         //return the sound event
00529         return bestSoundEvent;
00530 }

qboolean G_CheckForDanger gentity_t self,
int  alertEvent
 

Definition at line 537 of file NPC_senses.c.

References AEL_DANGER, level_locals_t::alertEvents, gentity_s::client, gentity_t, alertEvent_s::level, level, gentity_s::NPC, NPC_StartFlee(), alertEvent_s::owner, gclient_s::playerTeam, alertEvent_s::position, qboolean, qfalse, qtrue, SCF_DONT_FLEE, and gNPC_t::scriptFlags.

Referenced by NPC_CheckForDanger().

00538 {//FIXME: more bStates need to call this?
00539         if ( alertEvent == -1 )
00540         {
00541                 return qfalse;
00542         }
00543 
00544         if ( level.alertEvents[alertEvent].level >= AEL_DANGER )
00545         {//run away!
00546                 if ( !level.alertEvents[alertEvent].owner || !level.alertEvents[alertEvent].owner->client || (level.alertEvents[alertEvent].owner!=self&&level.alertEvents[alertEvent].owner->client->playerTeam!=self->client->playerTeam) )
00547                 {
00548                         if ( self->NPC )
00549                         {
00550                                 if ( self->NPC->scriptFlags & SCF_DONT_FLEE )
00551                                 {//can't flee
00552                                         return qfalse;
00553                                 }
00554                                 else
00555                                 {
00556                                         NPC_StartFlee( level.alertEvents[alertEvent].owner, level.alertEvents[alertEvent].position, level.alertEvents[alertEvent].level, 3000, 6000 );
00557                                         return qtrue;
00558                                 }
00559                         }
00560                         else
00561                         {
00562                                 return qtrue;
00563                         }
00564                 }
00565         }
00566         return qfalse;
00567 }

qboolean G_ClearLineOfSight const vec3_t  point1,
const vec3_t  point2,
int  ignore,
int  clipmask
 

Definition at line 11 of file NPC_senses.c.

References trace_t::endpos, EntIsGlass(), trace_t::entityNum, trace_t::fraction, g_entities, gentity_t, NULL, entityState_s::number, qboolean, qfalse, qtrue, gentity_s::s, trap_Trace(), vec3_t, and VectorCopy.

Referenced by G_FindLocalInterestPoint().

00012 {
00013         trace_t         tr;
00014         gentity_t       *hit;
00015 
00016         trap_Trace ( &tr, point1, NULL, NULL, point2, ignore, clipmask );
00017         if ( tr.fraction == 1.0 ) 
00018         {
00019                 return qtrue;
00020         }
00021 
00022         hit = &g_entities[ tr.entityNum ];
00023         if(EntIsGlass(hit))
00024         {
00025                 vec3_t  newpoint1;
00026                 VectorCopy(tr.endpos, newpoint1);
00027                 trap_Trace (&tr, newpoint1, NULL, NULL, point2, hit->s.number, clipmask );
00028 
00029                 if ( tr.fraction == 1.0 ) 
00030                 {
00031                         return qtrue;
00032                 }
00033         }
00034 
00035         return qfalse;
00036 }

qboolean G_ClearLOS gentity_t self,
const vec3_t  start,
const vec3_t  end
 

Definition at line 739 of file NPC_senses.c.

References CONTENTS_OPAQUE, trace_t::endpos, trace_t::entityNum, ENTITYNUM_NONE, ENTITYNUM_WORLD, trace_t::fraction, g_entities, gentity_t, MASK_OPAQUE, NULL, qboolean, qfalse, qtrue, SVF_GLASS_BRUSH, trap_Trace(), and vec3_t.

Referenced by G_ClearLOS2(), G_ClearLOS3(), G_ClearLOS5(), and NPC_ClearLOS().

00740 {
00741         trace_t         tr;
00742         int                     traceCount = 0;
00743         
00744         //FIXME: ENTITYNUM_NONE ok?
00745         trap_Trace ( &tr, start, NULL, NULL, end, ENTITYNUM_NONE, CONTENTS_OPAQUE/*CONTENTS_SOLID*//*(CONTENTS_SOLID|CONTENTS_MONSTERCLIP)*/ );
00746         while ( tr.fraction < 1.0 && traceCount < 3 )
00747         {//can see through 3 panes of glass
00748                 if ( tr.entityNum < ENTITYNUM_WORLD )
00749                 {
00750                         if ( &g_entities[tr.entityNum] != NULL && (g_entities[tr.entityNum].r.svFlags&SVF_GLASS_BRUSH) )
00751                         {//can see through glass, trace again, ignoring me
00752                                 trap_Trace ( &tr, tr.endpos, NULL, NULL, end, tr.entityNum, MASK_OPAQUE );
00753                                 traceCount++;
00754                                 continue;
00755                         }
00756                 }
00757                 return qfalse;
00758         }
00759 
00760         if ( tr.fraction == 1.0 ) 
00761                 return qtrue;
00762 
00763         return qfalse;
00764 }

qboolean G_ClearLOS2 gentity_t self,
gentity_t ent,
const vec3_t  end
 

Definition at line 767 of file NPC_senses.c.

References CalcEntitySpot(), G_ClearLOS(), gentity_t, qboolean, SPOT_HEAD_LEAN, and vec3_t.

Referenced by NPC_ClearLOS2().

00768 {
00769         vec3_t  eyes;
00770 
00771         CalcEntitySpot( ent, SPOT_HEAD_LEAN, eyes );
00772 
00773         return G_ClearLOS( self, eyes, end );
00774 }

qboolean G_ClearLOS3 gentity_t self,
const vec3_t  start,
gentity_t ent
 

Definition at line 777 of file NPC_senses.c.

References CalcEntitySpot(), G_ClearLOS(), gentity_t, qboolean, qfalse, qtrue, SPOT_HEAD_LEAN, SPOT_ORIGIN, and vec3_t.

Referenced by G_ClearLOS4(), and NPC_ClearLOS3().

00778 {
00779         vec3_t          spot;
00780 
00781         //Look for the chest first
00782         CalcEntitySpot( ent, SPOT_ORIGIN, spot );
00783 
00784         if ( G_ClearLOS( self, start, spot ) )
00785                 return qtrue;
00786 
00787         //Look for the head next
00788         CalcEntitySpot( ent, SPOT_HEAD_LEAN, spot );
00789 
00790         if ( G_ClearLOS( self, start, spot ) )
00791                 return qtrue;
00792 
00793         return qfalse;
00794 }

qboolean G_ClearLOS4 gentity_t self,
gentity_t ent
 

Definition at line 797 of file NPC_senses.c.

References CalcEntitySpot(), G_ClearLOS3(), gentity_t, qboolean, SPOT_HEAD_LEAN, and vec3_t.

Referenced by NPC_ClearLOS4(), and WP_SaberStartMissileBlockCheck().

00798 {
00799         vec3_t  eyes;
00800 
00801         //Calculate my position
00802         CalcEntitySpot( self, SPOT_HEAD_LEAN, eyes );
00803         
00804         return G_ClearLOS3( self, eyes, ent );
00805 }

qboolean G_ClearLOS5 gentity_t self,
const vec3_t  end
 

Definition at line 808 of file NPC_senses.c.

References CalcEntitySpot(), G_ClearLOS(), gentity_t, qboolean, SPOT_HEAD_LEAN, and vec3_t.

Referenced by NPC_ClearLOS5().

00809 {
00810         vec3_t  eyes;
00811 
00812         //Calculate the my position
00813         CalcEntitySpot( self, SPOT_HEAD_LEAN, eyes );
00814         
00815         return G_ClearLOS( self, eyes, end );
00816 }

int G_FindLocalInterestPoint gentity_t self  ) 
 

Definition at line 871 of file NPC_senses.c.

References CalcEntitySpot(), ENTITYNUM_NONE, fabs(), G_ClearLineOfSight(), G_UseTargets2(), gentity_t, level_locals_t::interestPoints, level, MASK_OPAQUE, MAX_INTEREST_DIST, entityState_s::number, level_locals_t::numInterestPoints, interestPoint_t::origin, Q3_INFINITE, gentity_s::s, SPOT_HEAD_LEAN, interestPoint_t::target, trap_InPVS(), vec3_t, and VectorSubtract.

00872 {
00873         int             i, bestPoint = ENTITYNUM_NONE;
00874         float   dist, bestDist = Q3_INFINITE;
00875         vec3_t  diffVec, eyes;
00876 
00877         CalcEntitySpot( self, SPOT_HEAD_LEAN, eyes );
00878         for ( i = 0; i < level.numInterestPoints; i++ )
00879         {
00880                 //Don't ignore portals?  If through a portal, need to look at portal!
00881                 if ( trap_InPVS( level.interestPoints[i].origin, eyes ) )
00882                 {
00883                         VectorSubtract( level.interestPoints[i].origin, eyes, diffVec );
00884                         if ( (fabs(diffVec[0]) + fabs(diffVec[1])) / 2 < 48 &&
00885                                 fabs(diffVec[2]) > (fabs(diffVec[0]) + fabs(diffVec[1])) / 2 )
00886                         {//Too close to look so far up or down
00887                                 continue;
00888                         }
00889                         dist = VectorLengthSquared( diffVec );
00890                         //Some priority to more interesting points
00891                         //dist -= ((int)level.interestPoints[i].lookMode * 5) * ((int)level.interestPoints[i].lookMode * 5);
00892                         if ( dist < MAX_INTEREST_DIST && dist < bestDist )
00893                         {
00894                                 if ( G_ClearLineOfSight( eyes, level.interestPoints[i].origin, self->s.number, MASK_OPAQUE ) )
00895                                 {
00896                                         bestDist = dist;
00897                                         bestPoint = i;
00898                                 }
00899                         }
00900                 }
00901         }
00902         if ( bestPoint != ENTITYNUM_NONE && level.interestPoints[bestPoint].target )
00903         {
00904                 G_UseTargets2( self, self, level.interestPoints[bestPoint].target );
00905         }
00906         return bestPoint;
00907 }

float G_GetLightLevel vec3_t  pos,
vec3_t  fromDir
 

Definition at line 388 of file NPC_senses.c.

References vec3_t.

Referenced by G_CheckAlertEvents().

00389 {
00390         /*
00391         vec3_t  ambient={0}, directed, lightDir;
00392 
00393         cgi_R_GetLighting( pos, ambient, directed, lightDir );
00394         lightLevel = VectorLength( ambient ) + (VectorLength( directed )*DotProduct( lightDir, fromDir ));
00395         */
00396         float   lightLevel;
00397         //rwwFIXMEFIXME: ...this is evil. We can possibly read from the server BSP data, or load the lightmap along
00398         //with collision data and whatnot, but is it worth it?
00399         lightLevel = 255;
00400 
00401         return lightLevel;
00402 }

qboolean InFOV gentity_t ent,
gentity_t from,
int  hFOV,
int  vFOV
 

Definition at line 149 of file NPC_senses.c.

References AngleDelta(), entityState_s::angles, CalcEntitySpot(), gentity_s::client, renderInfo_s::eyeAngles, fabs(), gentity_t, PITCH, gclient_s::ps, qboolean, qfalse, qtrue, gclient_s::renderInfo, gentity_s::s, SPOT_HEAD, SPOT_HEAD_LEAN, SPOT_LEGS, SPOT_ORIGIN, vec3_origin, vec3_t, vectoangles(), VectorCopy, VectorSubtract, playerState_s::viewangles, and YAW.

Referenced by G_AlertTeam(), Jedi_CheckAmbushPlayer(), NPC_CheckEnemyStealth(), NPC_CheckSurrender(), NPC_CheckVisibility(), NPC_ShySpawn(), NPC_SomeoneLookingAtMe(), and NPC_TargetVisible().

00150 {
00151         vec3_t  eyes;
00152         vec3_t  spot;
00153         vec3_t  deltaVector;
00154         vec3_t  angles, fromAngles;
00155         vec3_t  deltaAngles;
00156 
00157         if( from->client )
00158         {
00159                 if( !VectorCompare( from->client->renderInfo.eyeAngles, vec3_origin ) )
00160                 {//Actual facing of tag_head!
00161                         //NOTE: Stasis aliens may have a problem with this?
00162                         VectorCopy( from->client->renderInfo.eyeAngles, fromAngles );
00163                 }
00164                 else
00165                 {
00166                         VectorCopy( from->client->ps.viewangles, fromAngles );
00167                 }
00168         }
00169         else
00170         {
00171                 VectorCopy(from->s.angles, fromAngles);
00172         }
00173 
00174         CalcEntitySpot( from, SPOT_HEAD_LEAN, eyes );
00175 
00176         CalcEntitySpot( ent, SPOT_ORIGIN, spot );
00177         VectorSubtract ( spot, eyes, deltaVector);
00178 
00179         vectoangles ( deltaVector, angles );
00180         deltaAngles[PITCH] = AngleDelta ( fromAngles[PITCH], angles[PITCH] );
00181         deltaAngles[YAW] = AngleDelta ( fromAngles[YAW], angles[YAW] );
00182         if ( fabs ( deltaAngles[PITCH] ) <= vFOV && fabs ( deltaAngles[YAW] ) <= hFOV ) 
00183         {
00184                 return qtrue;
00185         }
00186 
00187         CalcEntitySpot( ent, SPOT_HEAD, spot );
00188         VectorSubtract ( spot, eyes, deltaVector);
00189         vectoangles ( deltaVector, angles );
00190         deltaAngles[PITCH] = AngleDelta ( fromAngles[PITCH], angles[PITCH] );
00191         deltaAngles[YAW] = AngleDelta ( fromAngles[YAW], angles[YAW] );
00192         if ( fabs ( deltaAngles[PITCH] ) <= vFOV && fabs ( deltaAngles[YAW] ) <= hFOV ) 
00193         {
00194                 return qtrue;
00195         }
00196 
00197         CalcEntitySpot( ent, SPOT_LEGS, spot );
00198         VectorSubtract ( spot, eyes, deltaVector);
00199         vectoangles ( deltaVector, angles );
00200         deltaAngles[PITCH] = AngleDelta ( fromAngles[PITCH], angles[PITCH] );
00201         deltaAngles[YAW] = AngleDelta ( fromAngles[YAW], angles[YAW] );
00202         if ( fabs ( deltaAngles[PITCH] ) <= vFOV && fabs ( deltaAngles[YAW] ) <= hFOV ) 
00203         {
00204                 return qtrue;
00205         }
00206 
00207         return qfalse;
00208 }

qboolean InFOV2 vec3_t  origin,
gentity_t from,
int  hFOV,
int  vFOV
 

Definition at line 129 of file NPC_senses.c.

References entityState_s::angles, CalcEntitySpot(), gentity_s::client, gentity_t, InFOV3(), gclient_s::ps, qboolean, gentity_s::s, SPOT_HEAD, vec3_t, VectorCopy, and playerState_s::viewangles.

00130 {
00131         vec3_t  fromAngles, eyes;
00132 
00133         if( from->client )
00134         {
00135                 VectorCopy(from->client->ps.viewangles, fromAngles);
00136         }
00137         else
00138         {
00139                 VectorCopy(from->s.angles, fromAngles);
00140         }
00141 
00142         CalcEntitySpot( from, SPOT_HEAD, eyes );
00143 
00144         return InFOV3( origin, eyes, fromAngles, hFOV, vFOV );
00145 }

qboolean InFOV3 vec3_t  spot,
vec3_t  from,
vec3_t  fromAngles,
int  hFOV,
int  vFOV
 

Definition at line 109 of file NPC_senses.c.

References AngleDelta(), fabs(), PITCH, qboolean, qfalse, qtrue, vec3_t, vectoangles(), VectorSubtract, and YAW.

Referenced by InFOV2(), NPC_BSGrenadier_Attack(), Rancor_Combat(), Wampa_Combat(), and WP_SaberStartMissileBlockCheck().

00110 {
00111         vec3_t  deltaVector, angles, deltaAngles;
00112 
00113         VectorSubtract ( spot, from, deltaVector );
00114         vectoangles ( deltaVector, angles );
00115         
00116         deltaAngles[PITCH]      = AngleDelta ( fromAngles[PITCH], angles[PITCH] );
00117         deltaAngles[YAW]        = AngleDelta ( fromAngles[YAW], angles[YAW] );
00118 
00119         if ( fabs ( deltaAngles[PITCH] ) <= vFOV && fabs ( deltaAngles[YAW] ) <= hFOV ) 
00120         {
00121                 return qtrue;
00122         }
00123 
00124         return qfalse;
00125 }

qboolean InFront vec3_t  spot,
vec3_t  from,
vec3_t  fromAngles,
float  threshHold
 

Definition at line 82 of file NPC_senses.c.

References AngleVectors(), DotProduct, NULL, qboolean, vec3_t, VectorCopy, VectorNormalize(), and VectorSubtract.

Referenced by DoGripAction(), FindGenericEnemyIndex(), NPC_BSGM_Attack(), SeekerDroneUpdate(), WP_SaberCanBlock(), and WP_SabersCheckLock().

00083 {
00084         vec3_t  dir, forward, angles;
00085         float   dot;
00086 
00087         VectorSubtract( spot, from, dir );
00088         dir[2] = 0;
00089         VectorNormalize( dir );
00090 
00091         VectorCopy( fromAngles, angles );
00092         angles[0] = 0;
00093         AngleVectors( angles, forward, NULL, NULL );
00094 
00095         dot = DotProduct( dir, forward );
00096 
00097         return (dot > threshHold);
00098 }

qboolean InVisrange gentity_t ent  ) 
 

Definition at line 210 of file NPC_senses.c.

References CalcEntitySpot(), gentity_t, NPC, NPCInfo, qboolean, qfalse, qtrue, SPOT_HEAD_LEAN, SPOT_ORIGIN, gNPC_t::stats, vec3_t, VectorSubtract, and gNPCstats_e::visrange.

Referenced by NPC_CheckVisibility(), and NPC_PickEnemy().

00211 {//FIXME: make a calculate visibility for ents that takes into account
00212         //lighting, movement, turning, crouch/stand up, other anims, hide brushes, etc.
00213         vec3_t  eyes;
00214         vec3_t  spot;
00215         vec3_t  deltaVector;
00216         float   visrange = (NPCInfo->stats.visrange*NPCInfo->stats.visrange);
00217 
00218         CalcEntitySpot( NPC, SPOT_HEAD_LEAN, eyes );
00219 
00220         CalcEntitySpot( ent, SPOT_ORIGIN, spot );
00221         VectorSubtract ( spot, eyes, deltaVector);
00222 
00223         /*if(ent->client)
00224         {
00225                 float   vel, avel;
00226                 if(ent->client->ps.velocity[0] || ent->client->ps.velocity[1] || ent->client->ps.velocity[2])
00227                 {
00228                         vel = VectorLength(ent->client->ps.velocity);
00229                         if(vel > 128)
00230                         {
00231                                 visrange += visrange * (vel/256);
00232                         }
00233                 }
00234 
00235                 if(ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
00236                 {//FIXME: shouldn't they need to have line of sight to you to detect this?
00237                         avel = VectorLength(ent->avelocity);
00238                         if(avel > 15)
00239                         {
00240                                 visrange += visrange * (avel/60);
00241                         }
00242                 }
00243         }*/
00244 
00245         if(VectorLengthSquared(deltaVector) > visrange)
00246         {
00247                 return qfalse;
00248         }
00249 
00250         return qtrue;
00251 }

int NPC_CheckAlertEvents qboolean  checkSight,
qboolean  checkSound,
int  ignoreAlert,
qboolean  mustHaveOwner,
int  minAlertLevel
 

Definition at line 532 of file NPC_senses.c.

References gNPCstats_e::earshot, G_CheckAlertEvents(), NPC, NPCInfo, gNPC_t::stats, and gNPCstats_e::visrange.

Referenced by Jedi_CheckDanger(), NPC_BSDefault(), NPC_BSFollowLeader(), NPC_BSGrenadier_Attack(), NPC_BSGrenadier_Patrol(), NPC_BSSleep(), NPC_BSSniper_Attack(), NPC_BSSniper_Patrol(), NPC_BSST_Attack(), NPC_BSST_Investigate(), NPC_BSST_Patrol(), NPC_BSST_Sleep(), NPC_PickEnemyExt(), and ST_Commander().

00533 {
00534         return G_CheckAlertEvents( NPC, checkSight, checkSound, NPCInfo->stats.visrange, NPCInfo->stats.earshot, ignoreAlert, mustHaveOwner, minAlertLevel );
00535 }

qboolean NPC_CheckForDanger int  alertEvent  ) 
 

Definition at line 568 of file NPC_senses.c.

References G_CheckForDanger(), NPC, and qboolean.

Referenced by NPC_BSGrenadier_Attack(), NPC_BSGrenadier_Patrol(), NPC_BSSniper_Attack(), NPC_BSSniper_Patrol(), NPC_BSST_Attack(), NPC_BSST_Investigate(), and ST_Commander().

00569 {//FIXME: more bStates need to call this?
00570         return G_CheckForDanger( NPC, alertEvent );
00571 }

visibility_t NPC_CheckVisibility gentity_t ent,
int  flags
 

Definition at line 257 of file NPC_senses.c.

References CanSee(), CanShoot(), CHECK_360, CHECK_FOV, CHECK_PVS, CHECK_SHOOT, CHECK_VISRANGE, entityShared_t::currentOrigin, gentity_t, gNPCstats_e::hfov, InFOV(), InVisrange(), NPC, NPCInfo, gentity_s::r, gNPC_t::stats, trap_InPVS(), gNPCstats_e::vfov, VIS_360, VIS_FOV, VIS_NOT, VIS_PVS, VIS_SHOOT, and visibility_t.

Referenced by NPC_BSAdvanceFight(), NPC_BSFollowLeader(), NPC_BSHuntAndKill(), NPC_CheckCanAttack(), NPC_CheckPossibleEnemy(), NPC_PickAlly(), and NPC_PickEnemy().

00258 {
00259         // flags should never be 0
00260         if ( !flags ) 
00261         {
00262                 return VIS_NOT;
00263         }
00264 
00265         // check PVS
00266         if ( flags & CHECK_PVS ) 
00267         {
00268                 if ( !trap_InPVS ( ent->r.currentOrigin, NPC->r.currentOrigin ) ) 
00269                 {
00270                         return VIS_NOT;
00271                 }
00272         }
00273         if ( !(flags & (CHECK_360|CHECK_FOV|CHECK_SHOOT)) ) 
00274         {
00275                 return VIS_PVS;
00276         }
00277 
00278         // check within visrange
00279         if (flags & CHECK_VISRANGE)
00280         {
00281                 if( !InVisrange ( ent ) ) 
00282                 {
00283                         return VIS_PVS;
00284                 }
00285         }
00286 
00287         // check 360 degree visibility
00288         //Meaning has to be a direct line of site
00289         if ( flags & CHECK_360 ) 
00290         {
00291                 if ( !CanSee ( ent ) ) 
00292                 {
00293                         return VIS_PVS;
00294                 }
00295         }
00296         if ( !(flags & (CHECK_FOV|CHECK_SHOOT)) ) 
00297         {
00298                 return VIS_360;
00299         }
00300 
00301         // check FOV
00302         if ( flags & CHECK_FOV ) 
00303         {
00304                 if ( !InFOV ( ent, NPC, NPCInfo->stats.hfov, NPCInfo->stats.vfov) ) 
00305                 {
00306                         return VIS_360;
00307                 }
00308         }
00309 
00310         if ( !(flags & CHECK_SHOOT) ) 
00311         {
00312                 return VIS_FOV;
00313         }
00314 
00315         // check shootability
00316         if ( flags & CHECK_SHOOT ) 
00317         {
00318                 if ( !CanShoot ( ent, NPC ) ) 
00319                 {
00320                         return VIS_FOV;
00321                 }
00322         }
00323 
00324         return VIS_SHOOT;
00325 }

float NPC_GetHFOVPercentage vec3_t  spot,
vec3_t  from,
vec3_t  facing,
float  hFOV
 

Definition at line 824 of file NPC_senses.c.

References AngleDelta(), fabs(), vec3_t, vectoangles(), VectorSubtract, and YAW.

Referenced by NPC_BSFollowLeader(), and NPC_CheckEnemyStealth().

00825 {
00826         vec3_t  deltaVector, angles;
00827         float   delta;
00828 
00829         VectorSubtract ( spot, from, deltaVector );
00830 
00831         vectoangles ( deltaVector, angles );
00832         
00833         delta = fabs( AngleDelta ( facing[YAW], angles[YAW] ) );
00834 
00835         if ( delta > hFOV )
00836                 return 0.0f; 
00837 
00838         return ( ( hFOV - delta ) / hFOV );
00839 }

float NPC_GetVFOVPercentage vec3_t  spot,
vec3_t  from,
vec3_t  facing,
float  vFOV
 

Definition at line 847 of file NPC_senses.c.

References AngleDelta(), fabs(), PITCH, vec3_t, vectoangles(), and VectorSubtract.

Referenced by NPC_CheckEnemyStealth().

00848 {
00849         vec3_t  deltaVector, angles;
00850         float   delta;
00851 
00852         VectorSubtract ( spot, from, deltaVector );
00853 
00854         vectoangles ( deltaVector, angles );
00855         
00856         delta = fabs( AngleDelta ( facing[PITCH], angles[PITCH] ) );
00857 
00858         if ( delta > vFOV )
00859                 return 0.0f; 
00860 
00861         return ( ( vFOV - delta ) / vFOV );
00862 }

qboolean RemoveOldestAlert void   ) 
 

Definition at line 695 of file NPC_senses.c.

References alertEvent_t, level_locals_t::alertEvents, level, MAX_ALERT_EVENTS, memmove(), memset(), level_locals_t::numAlertEvents, Q3_INFINITE, qboolean, and alertEvent_s::timestamp.

Referenced by AddSightEvent(), and AddSoundEvent().

00696 {
00697         int     oldestEvent = -1, oldestTime = Q3_INFINITE;
00698         int i;
00699         //loop through them all (max 32)
00700         for ( i = 0; i < level.numAlertEvents; i++ )
00701         {
00702                 //see if the event is old enough to delete
00703                 if ( level.alertEvents[i].timestamp < oldestTime )
00704                 {
00705                         oldestEvent = i;
00706                         oldestTime = level.alertEvents[i].timestamp;
00707                 }
00708         }
00709         if ( oldestEvent != -1 )
00710         {
00711                 //drop the count
00712                 level.numAlertEvents--;
00713                 //shift the rest down
00714                 if ( level.numAlertEvents > 0 )
00715                 {//still have more in the array
00716                         if ( (oldestEvent+1) < MAX_ALERT_EVENTS )
00717                         {
00718                                 memmove( &level.alertEvents[oldestEvent], &level.alertEvents[oldestEvent+1], sizeof(alertEvent_t)*(MAX_ALERT_EVENTS-(oldestEvent+1) ) );
00719                         }
00720                 }
00721                 else
00722                 {//just clear this one... or should we clear the whole array?
00723                         memset( &level.alertEvents[oldestEvent], 0, sizeof( alertEvent_t ) );
00724                 }
00725         }
00726         //make sure this never drops below zero... if it does, something very very bad happened
00727         assert( level.numAlertEvents >= 0 );
00728         //return true is have room for one now
00729         return (level.numAlertEvents<MAX_ALERT_EVENTS);
00730 }

void SP_target_interest gentity_t self  ) 
 

Definition at line 915 of file NPC_senses.c.

References Com_Printf(), entityShared_t::currentOrigin, G_FreeEntity(), G_NewString(), gentity_t, level_locals_t::interestPoints, level, MAX_INTEREST_POINTS, level_locals_t::numInterestPoints, gentity_s::r, gentity_s::target, and VectorCopy.

00916 {//FIXME: rename point_interest
00917         if(level.numInterestPoints >= MAX_INTEREST_POINTS)
00918         {
00919                 Com_Printf("ERROR:  Too many interest points, limit is %d\n", MAX_INTEREST_POINTS);
00920                 G_FreeEntity(self);
00921                 return;
00922         }
00923 
00924         VectorCopy(self->r.currentOrigin, level.interestPoints[level.numInterestPoints].origin);
00925 
00926         if(self->target && self->target[0])
00927         {
00928                 level.interestPoints[level.numInterestPoints].target = G_NewString( self->target );
00929         }
00930 
00931         level.numInterestPoints++;
00932 
00933         G_FreeEntity(self);
00934 }


Variable Documentation

int eventClearTime
 

Definition at line 5 of file NPC_senses.c.

Referenced by ClearPlayerAlertEvents(), and CorpsePhysics().