codemp/game/NPC_AI_Grenadier.c File Reference

#include "b_local.h"
#include "g_nav.h"
#include "anims.h"
#include "../namespace_begin.h"
#include "../namespace_end.h"

Go to the source code of this file.

Defines

#define MAX_VIEW_DIST   1024
#define MAX_VIEW_SPEED   250
#define MAX_LIGHT_INTENSITY   255
#define MIN_LIGHT_THRESHOLD   0.1
#define DISTANCE_SCALE   0.25f
#define DISTANCE_THRESHOLD   0.075f
#define SPEED_SCALE   0.25f
#define FOV_SCALE   0.5f
#define LIGHT_SCALE   0.25f
#define REALIZE_THRESHOLD   0.6f
#define CAUTIOUS_THRESHOLD   ( REALIZE_THRESHOLD * 0.75 )

Enumerations

enum  { LSTATE_NONE = 0, LSTATE_UNDERFIRE, LSTATE_INVESTIGATE }

Functions

qboolean BG_SabersOff (playerState_t *ps)
void CG_DrawAlert (vec3_t origin, float rating)
void G_AddVoiceEvent (gentity_t *self, int event, int speakDebounceTime)
void G_SoundOnEnt (gentity_t *ent, soundChannel_t channel, const char *soundPath)
void NPC_TempLookTarget (gentity_t *self, int lookEntNum, int minLookTime, int maxLookTime)
qboolean G_ExpandPointToBBox (vec3_t point, const vec3_t mins, const vec3_t maxs, int ignore, int clipmask)
void NPC_AimAdjust (int change)
qboolean FlyingCreature (gentity_t *ent)
qboolean NPC_CheckPlayerTeamStealth (void)
void Grenadier_ClearTimers (gentity_t *ent)
void NPC_Grenadier_PlayConfusionSound (gentity_t *self)
void NPC_Grenadier_Pain (gentity_t *self, gentity_t *attacker, int damage)
void NPC_BSGrenadier_Patrol (void)
qboolean Grenadier_EvaluateShot (int hit)
void NPC_BSGrenadier_Attack (void)
void NPC_BSGrenadier_Default (void)


Define Documentation

#define CAUTIOUS_THRESHOLD   ( REALIZE_THRESHOLD * 0.75 )
 

Definition at line 30 of file NPC_AI_Grenadier.c.

Referenced by NPC_CheckEnemyStealth().

#define DISTANCE_SCALE   0.25f
 

Definition at line 23 of file NPC_AI_Grenadier.c.

Referenced by NPC_CheckEnemyStealth().

#define DISTANCE_THRESHOLD   0.075f
 

Definition at line 24 of file NPC_AI_Grenadier.c.

Referenced by NPC_CheckEnemyStealth().

#define FOV_SCALE   0.5f
 

Definition at line 26 of file NPC_AI_Grenadier.c.

Referenced by NPC_CheckEnemyStealth().

#define LIGHT_SCALE   0.25f
 

Definition at line 27 of file NPC_AI_Grenadier.c.

Referenced by NPC_CheckEnemyStealth().

#define MAX_LIGHT_INTENSITY   255
 

Definition at line 20 of file NPC_AI_Grenadier.c.

Referenced by NPC_CheckEnemyStealth().

#define MAX_VIEW_DIST   1024
 

Definition at line 18 of file NPC_AI_Grenadier.c.

Referenced by NPC_CheckEnemyStealth().

#define MAX_VIEW_SPEED   250
 

Definition at line 19 of file NPC_AI_Grenadier.c.

Referenced by NPC_CheckEnemyStealth().

#define MIN_LIGHT_THRESHOLD   0.1
 

Definition at line 21 of file NPC_AI_Grenadier.c.

Referenced by NPC_CheckEnemyStealth().

#define REALIZE_THRESHOLD   0.6f
 

Definition at line 29 of file NPC_AI_Grenadier.c.

Referenced by NPC_CheckEnemyStealth().

#define SPEED_SCALE   0.25f
 

Definition at line 25 of file NPC_AI_Grenadier.c.

Referenced by NPC_CheckEnemyStealth().


Enumeration Type Documentation

anonymous enum
 

Enumeration values:
LSTATE_NONE 
LSTATE_UNDERFIRE 
LSTATE_INVESTIGATE 

Definition at line 42 of file NPC_AI_Grenadier.c.

00043 {
00044         LSTATE_NONE = 0,
00045         LSTATE_UNDERFIRE,
00046         LSTATE_INVESTIGATE,
00047 };


Function Documentation

qboolean BG_SabersOff playerState_t ps  ) 
 

Definition at line 201 of file bg_pmove.c.

00202 {
00203         if ( !ps->saberHolstered )
00204         {
00205                 return qfalse;
00206         }
00207         if ( ps->fd.saberAnimLevelBase == SS_DUAL
00208                 || ps->fd.saberAnimLevelBase == SS_STAFF )
00209         {
00210                 if ( ps->saberHolstered < 2 )
00211                 {
00212                         return qfalse;
00213                 }
00214         }
00215         return qtrue;
00216 }

void CG_DrawAlert vec3_t  origin,
float  rating
 

qboolean FlyingCreature gentity_t ent  ) 
 

Definition at line 46 of file g_nav.c.

00047 {
00048         if (ent->client && ent->client->ps.gravity <= 0)
00049         {
00050                 return qtrue;
00051         }
00052         return qfalse;
00053 }

void G_AddVoiceEvent gentity_t self,
int  event,
int  speakDebounceTime
 

Definition at line 23 of file NPC_sounds.c.

00024 {
00025         if ( !self->NPC )
00026         {
00027                 return;
00028         }
00029 
00030         if ( !self->client || self->client->ps.pm_type >= PM_DEAD )
00031         {
00032                 return;
00033         }
00034 
00035         if ( self->NPC->blockedSpeechDebounceTime > level.time )
00036         {
00037                 return;
00038         }
00039 
00040         if ( trap_ICARUS_TaskIDPending( self, TID_CHAN_VOICE ) )
00041         {
00042                 return;
00043         }
00044 
00045         
00046         if ( (self->NPC->scriptFlags&SCF_NO_COMBAT_TALK) && ( (event >= EV_ANGER1 && event <= EV_VICTORY3) || (event >= EV_CHASE1 && event <= EV_SUSPICIOUS5) ) )//(event < EV_FF_1A || event > EV_FF_3C) && (event < EV_RESPOND1 || event > EV_MISSION3) )
00047         {
00048                 return;
00049         }
00050         
00051         if ( (self->NPC->scriptFlags&SCF_NO_ALERT_TALK) && (event >= EV_GIVEUP1 && event <= EV_SUSPICIOUS5) )
00052         {
00053                 return;
00054         }
00055         //FIXME: Also needs to check for teammates. Don't want
00056         //              everyone babbling at once
00057 
00058         //NOTE: was losing too many speech events, so we do it directly now, screw networking!
00059         //G_AddEvent( self, event, 0 );
00060         G_SpeechEvent( self, event );
00061 
00062         //won't speak again for 5 seconds (unless otherwise specified)
00063         self->NPC->blockedSpeechDebounceTime = level.time + ((speakDebounceTime==0) ? 5000 : speakDebounceTime);
00064 }

qboolean G_ExpandPointToBBox vec3_t  point,
const vec3_t  mins,
const vec3_t  maxs,
int  ignore,
int  clipmask
 

Definition at line 2087 of file g_utils.c.

02088 {
02089         trace_t tr;
02090         vec3_t  start, end;
02091         int i;
02092 
02093         VectorCopy( point, start );
02094         
02095         for ( i = 0; i < 3; i++ )
02096         {
02097                 VectorCopy( start, end );
02098                 end[i] += mins[i];
02099                 trap_Trace( &tr, start, vec3_origin, vec3_origin, end, ignore, clipmask );
02100                 if ( tr.allsolid || tr.startsolid )
02101                 {
02102                         return qfalse;
02103                 }
02104                 if ( tr.fraction < 1.0 )
02105                 {
02106                         VectorCopy( start, end );
02107                         end[i] += maxs[i]-(mins[i]*tr.fraction);
02108                         trap_Trace( &tr, start, vec3_origin, vec3_origin, end, ignore, clipmask );
02109                         if ( tr.allsolid || tr.startsolid )
02110                         {
02111                                 return qfalse;
02112                         }
02113                         if ( tr.fraction < 1.0 )
02114                         {
02115                                 return qfalse;
02116                         }
02117                         VectorCopy( end, start );
02118                 }
02119         }
02120         //expanded it, now see if it's all clear
02121         trap_Trace( &tr, start, mins, maxs, start, ignore, clipmask );
02122         if ( tr.allsolid || tr.startsolid )
02123         {
02124                 return qfalse;
02125         }
02126         VectorCopy( start, point );
02127         return qtrue;
02128 }

void G_SoundOnEnt gentity_t ent,
soundChannel_t  channel,
const char *  soundPath
 

void Grenadier_ClearTimers gentity_t ent  ) 
 

Definition at line 49 of file NPC_AI_Grenadier.c.

References gentity_t, and TIMER_Set().

00050 {
00051         TIMER_Set( ent, "chatter", 0 );
00052         TIMER_Set( ent, "duck", 0 );
00053         TIMER_Set( ent, "stand", 0 );
00054         TIMER_Set( ent, "shuffleTime", 0 );
00055         TIMER_Set( ent, "sleepTime", 0 );
00056         TIMER_Set( ent, "enemyLastVisible", 0 );
00057         TIMER_Set( ent, "roamTime", 0 );
00058         TIMER_Set( ent, "hideTime", 0 );
00059         TIMER_Set( ent, "attackDelay", 0 );     //FIXME: Slant for difficulty levels
00060         TIMER_Set( ent, "stick", 0 );
00061         TIMER_Set( ent, "scoutTime", 0 );
00062         TIMER_Set( ent, "flee", 0 );
00063 }

qboolean Grenadier_EvaluateShot int  hit  ) 
 

Definition at line 441 of file NPC_AI_Grenadier.c.

References gentity_s::enemy, g_entities, NPC, NULL, entityState_s::number, qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, SVF_GLASS_BRUSH, and entityShared_t::svFlags.

00442 {
00443         if ( !NPC->enemy )
00444         {
00445                 return qfalse;
00446         }
00447 
00448         if ( hit == NPC->enemy->s.number || (&g_entities[hit] != NULL && (g_entities[hit].r.svFlags&SVF_GLASS_BRUSH)) )
00449         {//can hit enemy or will hit glass, so shoot anyway
00450                 return qtrue;
00451         }
00452         return qfalse;
00453 }

void NPC_AimAdjust int  change  ) 
 

Definition at line 3098 of file NPC_combat.c.

03099 {
03100         if ( !TIMER_Exists( NPC, "aimDebounce" ) )
03101         {
03102                 int debounce = 500+(3-g_spskill.integer)*100;
03103                 TIMER_Set( NPC, "aimDebounce", Q_irand( debounce,debounce+1000 ) );
03104                 //int debounce = 1000+(3-g_spskill.integer)*500;
03105                 //TIMER_Set( NPC, "aimDebounce", Q_irand( debounce, debounce+2000 ) );
03106                 return;
03107         }
03108         if ( TIMER_Done( NPC, "aimDebounce" ) )
03109         {
03110                 int debounce;
03111 
03112                 NPCInfo->currentAim += change;
03113                 if ( NPCInfo->currentAim > NPCInfo->stats.aim )
03114                 {//can never be better than max aim
03115                         NPCInfo->currentAim = NPCInfo->stats.aim;
03116                 }
03117                 else if ( NPCInfo->currentAim < -30 )
03118                 {//can never be worse than this
03119                         NPCInfo->currentAim = -30;
03120                 }
03121 
03122                 //Com_Printf( "%s new aim = %d\n", NPC->NPC_type, NPCInfo->currentAim );
03123 
03124                 debounce = 500+(3-g_spskill.integer)*100;
03125                 TIMER_Set( NPC, "aimDebounce", Q_irand( debounce,debounce+1000 ) );
03126                 //int debounce = 1000+(3-g_spskill.integer)*500;
03127                 //TIMER_Set( NPC, "aimDebounce", Q_irand( debounce, debounce+2000 ) );
03128         }
03129 }

void NPC_BSGrenadier_Attack void   ) 
 

NPC->enemy )//

Definition at line 461 of file NPC_AI_Grenadier.c.

References AEL_DANGER, trace_t::allsolid, BG_SabersOff(), gentity_s::client, gentity_s::clipmask, entityShared_t::currentOrigin, gNPC_t::desiredPitch, gNPC_t::desiredYaw, DistanceHorizontalSquared(), gentity_s::enemy, gNPC_t::enemyLastSeenLocation, gNPC_t::enemyLastSeenTime, gclient_s::enemyTeam, trace_t::entityNum, trace_t::fraction, g_entities, gentity_t, gNPC_t::goalEntity, InFOV3(), gNPC_t::lastPathAngles, level, entityShared_t::maxs, entityShared_t::mins, NPC, NPC_AimAdjust(), NPC_BSGrenadier_Patrol(), NPC_ChangeWeapon(), NPC_CheckAlertEvents(), NPC_CheckEnemyExt(), NPC_CheckForDanger(), NPC_ClearLOS4(), NPC_FaceEnemy(), NPC_ShotEntity(), NPC_UpdateAngles(), NPCInfo, NULL, entityState_s::number, gentity_s::painDebounceTime, gclient_s::playerTeam, gclient_s::ps, qfalse, qtrue, gentity_s::r, gentity_s::s, playerState_s::saberHolstered, SCF_CHASE_ENEMIES, SCF_DONT_FIRE, SCF_FIRE_WEAPON, gNPC_t::scriptFlags, gNPC_t::shotTime, trace_t::startsolid, STAT_WEAPONS, playerState_s::stats, level_locals_t::time, TIMER_Done(), TIMER_Set(), trap_Trace(), ucmd, usercmd_s::upmove, VectorCopy, playerState_s::viewangles, playerState_s::weapon, WeaponThink(), WP_SABER, WP_STUN_BATON, WP_THERMAL, and YAW.

Referenced by NPC_BSGrenadier_Default().

00462 {
00463         //Don't do anything if we're hurt
00464         if ( NPC->painDebounceTime > level.time )
00465         {
00466                 NPC_UpdateAngles( qtrue, qtrue );
00467                 return;
00468         }
00469 
00470         //NPC_CheckEnemy( qtrue, qfalse );
00471         //If we don't have an enemy, just idle
00472         if ( NPC_CheckEnemyExt(qfalse) == qfalse )
00473         {
00474                 NPC->enemy = NULL;
00475                 NPC_BSGrenadier_Patrol();//FIXME: or patrol?
00476                 return;
00477         }
00478 
00479         if ( TIMER_Done( NPC, "flee" ) && NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_DANGER ) ) )
00480         {//going to run
00481                 NPC_UpdateAngles( qtrue, qtrue );
00482                 return;
00483         }
00484 
00485         if ( !NPC->enemy )
00486         {//WTF?  somehow we lost our enemy?
00487                 NPC_BSGrenadier_Patrol();//FIXME: or patrol?
00488                 return;
00489         }
00490 
00491         enemyLOS3 = enemyCS3 = qfalse;
00492         move3 = qtrue;
00493         faceEnemy3 = qfalse;
00494         shoot3 = qfalse;
00495         enemyDist3 = DistanceSquared( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin );
00496 
00497         //See if we should switch to melee attack
00498         if ( enemyDist3 < 16384 //128
00499                 && (!NPC->enemy->client
00500                         || NPC->enemy->client->ps.weapon != WP_SABER
00501                         || BG_SabersOff( &NPC->enemy->client->ps ) 
00502                         ) 
00503                 )
00504         {//enemy is close and not using saber
00505                 if ( NPC->client->ps.weapon == WP_THERMAL )
00506                 {//grenadier
00507                         trace_t trace;
00508                         trap_Trace ( &trace, NPC->r.currentOrigin, NPC->enemy->r.mins, NPC->enemy->r.maxs, NPC->enemy->r.currentOrigin, NPC->s.number, NPC->enemy->clipmask );
00509                         if ( !trace.allsolid && !trace.startsolid && (trace.fraction == 1.0 || trace.entityNum == NPC->enemy->s.number ) )
00510                         {//I can get right to him
00511                                 //reset fire-timing variables
00512                                 NPC_ChangeWeapon( WP_STUN_BATON );
00513                                 if ( !(NPCInfo->scriptFlags&SCF_CHASE_ENEMIES) )//NPCInfo->behaviorState == BS_STAND_AND_SHOOT )
00514                                 {//FIXME: should we be overriding scriptFlags?
00515                                         NPCInfo->scriptFlags |= SCF_CHASE_ENEMIES;//NPCInfo->behaviorState = BS_HUNT_AND_KILL;
00516                                 }
00517                         }
00518                 }
00519         }
00520         else if ( enemyDist3 > 65536 || (NPC->enemy->client && NPC->enemy->client->ps.weapon == WP_SABER && !NPC->enemy->client->ps.saberHolstered) )//256
00521         {//enemy is far or using saber
00522                 if ( NPC->client->ps.weapon == WP_STUN_BATON && (NPC->client->ps.stats[STAT_WEAPONS]&(1<<WP_THERMAL)) )
00523                 {//fisticuffs, make switch to thermal if have it
00524                         //reset fire-timing variables
00525                         NPC_ChangeWeapon( WP_THERMAL );
00526                 }
00527         }
00528 
00529         //can we see our target?
00530         if ( NPC_ClearLOS4( NPC->enemy ) )
00531         {
00532                 NPCInfo->enemyLastSeenTime = level.time;
00533                 enemyLOS3 = qtrue;
00534 
00535                 if ( NPC->client->ps.weapon == WP_STUN_BATON )
00536                 {
00537                         if ( enemyDist3 <= 4096 && InFOV3( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, NPC->client->ps.viewangles, 90, 45 ) )//within 64 & infront
00538                         {
00539                                 VectorCopy( NPC->enemy->r.currentOrigin, NPCInfo->enemyLastSeenLocation );
00540                                 enemyCS3 = qtrue;
00541                         }
00542                 }
00543                 else if ( InFOV3( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, NPC->client->ps.viewangles, 45, 90 ) )
00544                 {//in front of me 
00545                         //can we shoot our target?
00546                         //FIXME: how accurate/necessary is this check?
00547                         int hit = NPC_ShotEntity( NPC->enemy, NULL );
00548                         gentity_t *hitEnt = &g_entities[hit];
00549                         if ( hit == NPC->enemy->s.number 
00550                                 || ( hitEnt && hitEnt->client && hitEnt->client->playerTeam == NPC->client->enemyTeam ) )
00551                         {
00552                                 float enemyHorzDist;
00553 
00554                                 VectorCopy( NPC->enemy->r.currentOrigin, NPCInfo->enemyLastSeenLocation );
00555                                 enemyHorzDist = DistanceHorizontalSquared( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin );
00556                                 if ( enemyHorzDist < 1048576 )
00557                                 {//within 1024
00558                                         enemyCS3 = qtrue;
00559                                         NPC_AimAdjust( 2 );//adjust aim better longer we have clear shot at enemy
00560                                 }
00561                                 else
00562                                 {
00563                                         NPC_AimAdjust( 1 );//adjust aim better longer we can see enemy
00564                                 }
00565                         }
00566                 }
00567         }
00568         else
00569         {
00570                 NPC_AimAdjust( -1 );//adjust aim worse longer we cannot see enemy
00571         }
00572         /*
00573         else if ( trap_InPVS( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin ) )
00574         {
00575                 NPCInfo->enemyLastSeenTime = level.time;
00576                 faceEnemy3 = qtrue;
00577         }
00578         */
00579 
00580         if ( enemyLOS3 )
00581         {//FIXME: no need to face enemy if we're moving to some other goal and he's too far away to shoot?
00582                 faceEnemy3 = qtrue;
00583         }
00584 
00585         if ( enemyCS3 )
00586         {
00587                 shoot3 = qtrue;
00588                 if ( NPC->client->ps.weapon == WP_THERMAL )
00589                 {//don't chase and throw
00590                         move3 = qfalse;
00591                 }
00592                 else if ( NPC->client->ps.weapon == WP_STUN_BATON && enemyDist3 < (NPC->r.maxs[0]+NPC->enemy->r.maxs[0]+16)*(NPC->r.maxs[0]+NPC->enemy->r.maxs[0]+16) )
00593                 {//close enough
00594                         move3 = qfalse;
00595                 }
00596         }//this should make him chase enemy when out of range...?
00597 
00598         //Check for movement to take care of
00599         Grenadier_CheckMoveState();
00600 
00601         //See if we should override shooting decision with any special considerations
00602         Grenadier_CheckFireState();
00603 
00604         if ( move3 )
00605         {//move toward goal
00606                 if ( NPCInfo->goalEntity )//&& ( NPCInfo->goalEntity != NPC->enemy || enemyDist3 > 10000 ) )//100 squared
00607                 {
00608                         move3 = Grenadier_Move();
00609                 }
00610                 else
00611                 {
00612                         move3 = qfalse;
00613                 }
00614         }
00615 
00616         if ( !move3 )
00617         {
00618                 if ( !TIMER_Done( NPC, "duck" ) )
00619                 {
00620                         ucmd.upmove = -127;
00621                 }
00622                 //FIXME: what about leaning?
00623         }
00624         else
00625         {//stop ducking!
00626                 TIMER_Set( NPC, "duck", -1 );
00627         }
00628 
00629         if ( !faceEnemy3 )
00630         {//we want to face in the dir we're running
00631                 if ( move3 )
00632                 {//don't run away and shoot
00633                         NPCInfo->desiredYaw = NPCInfo->lastPathAngles[YAW];
00634                         NPCInfo->desiredPitch = 0;
00635                         shoot3 = qfalse;
00636                 }
00637                 NPC_UpdateAngles( qtrue, qtrue );
00638         }
00639         else// if ( faceEnemy3 )
00640         {//face the enemy
00641                 NPC_FaceEnemy(qtrue);
00642         }
00643 
00644         if ( NPCInfo->scriptFlags&SCF_DONT_FIRE )
00645         {
00646                 shoot3 = qfalse;
00647         }
00648 
00649         //FIXME: don't shoot right away!
00650         if ( shoot3 )
00651         {//try to shoot if it's time
00652                 if ( TIMER_Done( NPC, "attackDelay" ) )
00653                 {       
00654                         if( !(NPCInfo->scriptFlags & SCF_FIRE_WEAPON) ) // we've already fired, no need to do it again here
00655                         {
00656                                 WeaponThink( qtrue );
00657                                 TIMER_Set( NPC, "attackDelay", NPCInfo->shotTime-level.time );
00658                         }
00659                         
00660                 }
00661         }
00662 }

void NPC_BSGrenadier_Default void   ) 
 

Definition at line 664 of file NPC_AI_Grenadier.c.

References gentity_s::enemy, NPC, NPC_BSGrenadier_Attack(), NPC_BSGrenadier_Patrol(), NPCInfo, qtrue, SCF_FIRE_WEAPON, gNPC_t::scriptFlags, and WeaponThink().

Referenced by NPC_BehaviorSet_Grenadier().

00665 {
00666         if( NPCInfo->scriptFlags & SCF_FIRE_WEAPON )
00667         {
00668                 WeaponThink( qtrue );
00669         }
00670 
00671         if( !NPC->enemy )
00672         {//don't have an enemy, look for one
00673                 NPC_BSGrenadier_Patrol();
00674         }
00675         else//if ( NPC->enemy )
00676         {//have an enemy
00677                 NPC_BSGrenadier_Attack();
00678         }
00679 }

void NPC_BSGrenadier_Patrol void   ) 
 

Definition at line 190 of file NPC_AI_Grenadier.c.

References AEL_DISCOVERED, AEL_SUSPICIOUS, level_locals_t::alertEvents, BUTTON_WALKING, usercmd_s::buttons, gentity_s::client, gNPC_t::confusionTime, gNPC_t::desiredPitch, gNPC_t::desiredYaw, gclient_s::enemyTeam, renderInfo_s::eyePoint, G_SetEnemy(), gentity_s::health, alertEvent_s::ID, gNPC_t::investigateDebounceTime, gNPC_t::investigateGoal, gNPC_t::lastAlertID, alertEvent_s::level, level, NPC, NPC_CheckAlertEvents(), NPC_CheckForDanger(), NPC_CheckPlayerTeamStealth(), NPC_MoveToGoal(), NPC_UpdateAngles(), NPCInfo, alertEvent_s::owner, PITCH, gclient_s::playerTeam, alertEvent_s::position, Q_irand(), qfalse, qtrue, gclient_s::renderInfo, SCF_IGNORE_ALERTS, SCF_LOOK_FOR_ENEMIES, gNPC_t::scriptFlags, level_locals_t::time, TIMER_Set(), ucmd, UpdateGoal(), vec3_t, vectoangles(), VectorCopy, VectorSubtract, and YAW.

Referenced by NPC_BSGrenadier_Attack(), and NPC_BSGrenadier_Default().

00191 {//FIXME: pick up on bodies of dead buddies?
00192         if ( NPCInfo->confusionTime < level.time )
00193         {
00194                 //Look for any enemies
00195                 if ( NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES )
00196                 {
00197                         if ( NPC_CheckPlayerTeamStealth() )
00198                         {
00199                                 //NPCInfo->behaviorState = BS_HUNT_AND_KILL;//should be automatic now
00200                                 //NPC_AngerSound();
00201                                 NPC_UpdateAngles( qtrue, qtrue );
00202                                 return;
00203                         }
00204                 }
00205 
00206                 if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) )
00207                 {
00208                         //Is there danger nearby
00209                         int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_SUSPICIOUS );
00210                         if ( NPC_CheckForDanger( alertEvent ) )
00211                         {
00212                                 NPC_UpdateAngles( qtrue, qtrue );
00213                                 return;
00214                         }
00215                         else
00216                         {//check for other alert events
00217                                 //There is an event to look at
00218                                 if ( alertEvent >= 0 && level.alertEvents[alertEvent].ID != NPCInfo->lastAlertID )
00219                                 {
00220                                         NPCInfo->lastAlertID = level.alertEvents[alertEvent].ID;
00221                                         if ( level.alertEvents[alertEvent].level == AEL_DISCOVERED )
00222                                         {
00223                                                 if ( level.alertEvents[alertEvent].owner && 
00224                                                         level.alertEvents[alertEvent].owner->client && 
00225                                                         level.alertEvents[alertEvent].owner->health >= 0 &&
00226                                                         level.alertEvents[alertEvent].owner->client->playerTeam == NPC->client->enemyTeam )
00227                                                 {//an enemy
00228                                                         G_SetEnemy( NPC, level.alertEvents[alertEvent].owner );
00229                                                         //NPCInfo->enemyLastSeenTime = level.time;
00230                                                         TIMER_Set( NPC, "attackDelay", Q_irand( 500, 2500 ) );
00231                                                 }
00232                                         }
00233                                         else
00234                                         {//FIXME: get more suspicious over time?
00235                                                 //Save the position for movement (if necessary)
00236                                                 VectorCopy( level.alertEvents[alertEvent].position, NPCInfo->investigateGoal );
00237                                                 NPCInfo->investigateDebounceTime = level.time + Q_irand( 500, 1000 );
00238                                                 if ( level.alertEvents[alertEvent].level == AEL_SUSPICIOUS )
00239                                                 {//suspicious looks longer
00240                                                         NPCInfo->investigateDebounceTime += Q_irand( 500, 2500 );
00241                                                 }
00242                                         }
00243                                 }
00244                         }
00245 
00246                         if ( NPCInfo->investigateDebounceTime > level.time )
00247                         {//FIXME: walk over to it, maybe?  Not if not chase enemies
00248                                 //NOTE: stops walking or doing anything else below
00249                                 vec3_t  dir, angles;
00250                                 float   o_yaw, o_pitch;
00251                                 
00252                                 VectorSubtract( NPCInfo->investigateGoal, NPC->client->renderInfo.eyePoint, dir );
00253                                 vectoangles( dir, angles );
00254                                 
00255                                 o_yaw = NPCInfo->desiredYaw;
00256                                 o_pitch = NPCInfo->desiredPitch;
00257                                 NPCInfo->desiredYaw = angles[YAW];
00258                                 NPCInfo->desiredPitch = angles[PITCH];
00259                                 
00260                                 NPC_UpdateAngles( qtrue, qtrue );
00261 
00262                                 NPCInfo->desiredYaw = o_yaw;
00263                                 NPCInfo->desiredPitch = o_pitch;
00264                                 return;
00265                         }
00266                 }
00267         }
00268 
00269         //If we have somewhere to go, then do that
00270         if ( UpdateGoal() )
00271         {
00272                 ucmd.buttons |= BUTTON_WALKING;
00273                 NPC_MoveToGoal( qtrue );
00274         }
00275 
00276         NPC_UpdateAngles( qtrue, qtrue );
00277 }

qboolean NPC_CheckPlayerTeamStealth void   ) 
 

void NPC_Grenadier_Pain gentity_t self,
gentity_t attacker,
int  damage
 

Definition at line 90 of file NPC_AI_Grenadier.c.

References EV_PUSHED1, EV_PUSHED3, G_AddVoiceEvent(), gentity_t, gentity_s::health, gNPC_t::localState, LSTATE_UNDERFIRE, gentity_s::NPC, NPC_Pain(), Q_irand(), and TIMER_Set().

00091 {
00092         self->NPC->localState = LSTATE_UNDERFIRE;
00093 
00094         TIMER_Set( self, "duck", -1 );
00095         TIMER_Set( self, "stand", 2000 );
00096 
00097         NPC_Pain( self, attacker, damage );
00098 
00099         if ( !damage && self->health > 0 )
00100         {//FIXME: better way to know I was pushed
00101                 G_AddVoiceEvent( self, Q_irand(EV_PUSHED1, EV_PUSHED3), 2000 );
00102         }
00103 }

void NPC_Grenadier_PlayConfusionSound gentity_t self  ) 
 

Definition at line 65 of file NPC_AI_Grenadier.c.

References BS_DEFAULT, EV_CONFUSE1, EV_CONFUSE3, G_AddVoiceEvent(), G_ClearEnemy(), gentity_t, gentity_s::health, gNPC_t::investigateCount, gentity_s::NPC, Q_irand(), SQUAD_IDLE, gNPC_t::squadState, gNPC_t::tempBehavior, and TIMER_Set().

00066 {//FIXME: make this a custom sound in sound set
00067         if ( self->health > 0 )
00068         {
00069                 G_AddVoiceEvent( self, Q_irand(EV_CONFUSE1, EV_CONFUSE3), 2000 );
00070         }
00071         //reset him to be totally unaware again
00072         TIMER_Set( self, "enemyLastVisible", 0 );
00073         TIMER_Set( self, "flee", 0 );
00074         self->NPC->squadState = SQUAD_IDLE;
00075         self->NPC->tempBehavior = BS_DEFAULT;
00076         
00077         //self->NPC->behaviorState = BS_PATROL;
00078         G_ClearEnemy( self );//FIXME: or just self->enemy = NULL;?
00079 
00080         self->NPC->investigateCount = 0;
00081 }

void NPC_TempLookTarget gentity_t self,
int  lookEntNum,
int  minLookTime,
int  maxLookTime
 

Definition at line 661 of file NPC_reactions.c.

00662 {
00663         if ( !self->client )
00664         {
00665                 return;
00666         }
00667 
00668         if ( (self->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
00669         {//lookTarget is set by and to the monster that's holding you, no other operations can change that
00670                 return;
00671         }
00672 
00673         if ( !minLookTime )
00674         {
00675                 minLookTime = 1000;
00676         }
00677 
00678         if ( !maxLookTime )
00679         {
00680                 maxLookTime = 1000;
00681         }
00682 
00683         if ( !NPC_CheckLookTarget( self ) )
00684         {//Not already looking at something else
00685                 //Look at him for 1 to 3 seconds
00686                 NPC_SetLookTarget( self, lookEntNum, level.time + Q_irand( minLookTime, maxLookTime ) );
00687         }
00688 }