codemp/game/NPC_AI_Sentry.c File Reference

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

Go to the source code of this file.

Defines

#define MIN_DISTANCE   256
#define MIN_DISTANCE_SQR   ( MIN_DISTANCE * MIN_DISTANCE )
#define SENTRY_FORWARD_BASE_SPEED   10
#define SENTRY_FORWARD_MULTIPLIER   5
#define SENTRY_VELOCITY_DECAY   0.85f
#define SENTRY_STRAFE_VEL   256
#define SENTRY_STRAFE_DIS   200
#define SENTRY_UPWARD_PUSH   32
#define SENTRY_HOVER_HEIGHT   24

Enumerations

enum  {
  LSTATE_NONE = 0, LSTATE_ASLEEP, LSTATE_WAKEUP, LSTATE_ACTIVE,
  LSTATE_POWERING_UP, LSTATE_ATTACKING
}

Functions

gitem_tBG_FindItemForAmmo (ammo_t ammo)
void G_SoundOnEnt (gentity_t *ent, soundChannel_t channel, const char *soundPath)
void NPC_Sentry_Precache (void)
void sentry_use (gentity_t *self, gentity_t *other, gentity_t *activator)
void NPC_Sentry_Pain (gentity_t *self, gentity_t *attacker, int damage)
void Sentry_Fire (void)
void Sentry_MaintainHeight (void)
void Sentry_Idle (void)
void Sentry_Strafe (void)
void Sentry_Hunt (qboolean visible, qboolean advance)
void Sentry_RangedAttack (qboolean visible, qboolean advance)
void Sentry_AttackDecision (void)
qboolean NPC_CheckPlayerTeamStealth (void)
void NPC_Sentry_Patrol (void)
void NPC_BSSentry_Default (void)


Define Documentation

#define MIN_DISTANCE   256
 

Definition at line 9 of file NPC_AI_Sentry.c.

#define MIN_DISTANCE_SQR   ( MIN_DISTANCE * MIN_DISTANCE )
 

Definition at line 10 of file NPC_AI_Sentry.c.

#define SENTRY_FORWARD_BASE_SPEED   10
 

Definition at line 12 of file NPC_AI_Sentry.c.

Referenced by Sentry_Hunt().

#define SENTRY_FORWARD_MULTIPLIER   5
 

Definition at line 13 of file NPC_AI_Sentry.c.

Referenced by Sentry_Hunt().

#define SENTRY_HOVER_HEIGHT   24
 

Definition at line 19 of file NPC_AI_Sentry.c.

Referenced by Sentry_MaintainHeight().

#define SENTRY_STRAFE_DIS   200
 

Definition at line 17 of file NPC_AI_Sentry.c.

Referenced by Sentry_Strafe().

#define SENTRY_STRAFE_VEL   256
 

Definition at line 16 of file NPC_AI_Sentry.c.

Referenced by Sentry_Strafe().

#define SENTRY_UPWARD_PUSH   32
 

Definition at line 18 of file NPC_AI_Sentry.c.

Referenced by Sentry_Strafe().

#define SENTRY_VELOCITY_DECAY   0.85f
 

Definition at line 15 of file NPC_AI_Sentry.c.

Referenced by Sentry_MaintainHeight().


Enumeration Type Documentation

anonymous enum
 

Enumeration values:
LSTATE_NONE 
LSTATE_ASLEEP 
LSTATE_WAKEUP 
LSTATE_ACTIVE 
LSTATE_POWERING_UP 
LSTATE_ATTACKING 

Definition at line 22 of file NPC_AI_Sentry.c.

00023 {
00024         LSTATE_NONE = 0,
00025         LSTATE_ASLEEP,
00026         LSTATE_WAKEUP,
00027         LSTATE_ACTIVE,
00028         LSTATE_POWERING_UP,
00029         LSTATE_ATTACKING,
00030 };


Function Documentation

gitem_t* BG_FindItemForAmmo ammo_t  ammo  ) 
 

Definition at line 1941 of file bg_misc.c.

References bg_itemlist, gitem_s::classname, Com_Error(), ERR_DROP, gitem_s::giTag, gitem_t, gitem_s::giType, IT_AMMO, and NULL.

Referenced by NPC_Mark1_Precache(), NPC_Mark2_Precache(), NPC_Probe_Precache(), NPC_Sentry_Precache(), and NPC_ShadowTrooper_Precache().

01941                                            {
01942         gitem_t *it;
01943         
01944         for ( it = bg_itemlist + 1 ; it->classname ; it++) {
01945                 if ( it->giType == IT_AMMO && it->giTag == ammo ) {
01946                         return it;
01947                 }
01948         }
01949 
01950         Com_Error( ERR_DROP, "Couldn't find item for ammo %i", ammo);
01951         return NULL;
01952 }

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

void NPC_BSSentry_Default void   ) 
 

Definition at line 557 of file NPC_AI_Sentry.c.

References gentity_s::enemy, gNPC_t::localState, LSTATE_WAKEUP, NPC, NPC_Sentry_Patrol(), NPCInfo, SCF_LOOK_FOR_ENEMIES, gNPC_t::scriptFlags, Sentry_AttackDecision(), Sentry_Idle(), sentry_use(), gentity_s::targetname, and gentity_s::use.

Referenced by NPC_BehaviorSet_Sentry().

00558 {
00559         if ( NPC->targetname )
00560         {
00561                 NPC->use = sentry_use;
00562         }
00563 
00564         if (( NPC->enemy ) && (NPCInfo->localState != LSTATE_WAKEUP))
00565         {
00566                 // Don't attack if waking up or if no enemy
00567                 Sentry_AttackDecision();
00568         }
00569         else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
00570         {
00571                 NPC_Sentry_Patrol();
00572         }
00573         else
00574         {
00575                 Sentry_Idle();
00576         }
00577 }

qboolean NPC_CheckPlayerTeamStealth void   ) 
 

void NPC_Sentry_Pain gentity_t self,
gentity_t attacker,
int  damage
 

Definition at line 79 of file NPC_AI_Sentry.c.

References BOTH_FLY_SHIELDED, gNPC_t::burstCount, CHAN_AUTO, FL_SHIELDED, gentity_s::flags, G_Sound(), G_SoundIndex(), gentity_t, gPainMOD, gNPC_t::localState, LSTATE_ACTIVE, MOD_DEMP2, MOD_DEMP2_ALT, gentity_s::NPC, NPC_Pain(), NPC_SetAnim(), Q_irand(), SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, and TIMER_Set().

Referenced by NPC_PainFunc().

00080 {               
00081         int mod = gPainMOD;
00082 
00083         NPC_Pain( self, attacker, damage );
00084 
00085         if ( mod == MOD_DEMP2 || mod == MOD_DEMP2_ALT )
00086         {
00087                 self->NPC->burstCount = 0;
00088                 TIMER_Set( self, "attackDelay", Q_irand( 9000, 12000) );
00089                 self->flags |= FL_SHIELDED;
00090                 NPC_SetAnim( self, SETANIM_BOTH, BOTH_FLY_SHIELDED, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00091                 G_Sound( self, CHAN_AUTO, G_SoundIndex("sound/chars/sentry/misc/sentry_pain") );                
00092 
00093                 self->NPC->localState = LSTATE_ACTIVE;
00094         }
00095 
00096         // You got hit, go after the enemy
00097 //      if (self->NPC->localState == LSTATE_ASLEEP)
00098 //      {
00099 //              G_Sound( self, G_SoundIndex("sound/chars/sentry/misc/shieldsopen.wav"));
00100 //
00101 //              self->flags &= ~FL_SHIELDED;
00102 //              NPC_SetAnim( self, SETANIM_BOTH, BOTH_POWERUP1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00103 //              self->NPC->localState = LSTATE_WAKEUP;
00104 //      }
00105 }

void NPC_Sentry_Patrol void   ) 
 

Definition at line 519 of file NPC_AI_Sentry.c.

References BUTTON_WALKING, usercmd_s::buttons, CHAN_AUTO, gentity_s::enemy, G_SoundOnEnt(), NPC, NPC_CheckPlayerTeamStealth(), NPC_MoveToGoal(), NPC_UpdateAngles(), Q_irand(), qtrue, Sentry_MaintainHeight(), TIMER_Done(), TIMER_Set(), ucmd, UpdateGoal(), and va().

Referenced by NPC_BSSentry_Default().

00520 {
00521         Sentry_MaintainHeight();
00522 
00523         //If we have somewhere to go, then do that
00524         if (!NPC->enemy)
00525         {
00526                 if ( NPC_CheckPlayerTeamStealth() )
00527                 {
00528                         //NPC_AngerSound();
00529                         NPC_UpdateAngles( qtrue, qtrue );
00530                         return;
00531                 }
00532 
00533                 if ( UpdateGoal() )
00534                 {
00535                         //start loop sound once we move
00536                         ucmd.buttons |= BUTTON_WALKING;
00537                         NPC_MoveToGoal( qtrue );
00538                 }
00539 
00540                 //randomly talk
00541                 if (TIMER_Done(NPC,"patrolNoise"))
00542                 {
00543                         G_SoundOnEnt( NPC, CHAN_AUTO, va("sound/chars/sentry/misc/talk%d", Q_irand(1, 3)) );
00544 
00545                         TIMER_Set( NPC, "patrolNoise", Q_irand( 2000, 4000 ) );
00546                 }
00547         }
00548 
00549         NPC_UpdateAngles( qtrue, qtrue );
00550 }

void NPC_Sentry_Precache void   ) 
 

Definition at line 37 of file NPC_AI_Sentry.c.

References AMMO_BLASTER, BG_FindItemForAmmo(), G_EffectIndex(), G_SoundIndex(), RegisterItem(), and va().

Referenced by NPC_SpawnType(), and SP_NPC_Droid_Sentry().

00038 {
00039         int i;
00040 
00041         G_SoundIndex( "sound/chars/sentry/misc/sentry_explo" );
00042         G_SoundIndex( "sound/chars/sentry/misc/sentry_pain" );
00043         G_SoundIndex( "sound/chars/sentry/misc/sentry_shield_open" );
00044         G_SoundIndex( "sound/chars/sentry/misc/sentry_shield_close" );
00045         G_SoundIndex( "sound/chars/sentry/misc/sentry_hover_1_lp" );
00046         G_SoundIndex( "sound/chars/sentry/misc/sentry_hover_2_lp" );
00047 
00048         for ( i = 1; i < 4; i++)
00049         {
00050                 G_SoundIndex( va( "sound/chars/sentry/misc/talk%d", i ) );
00051         }
00052 
00053         G_EffectIndex( "bryar/muzzle_flash");
00054         G_EffectIndex( "env/med_explode");
00055 
00056         RegisterItem( BG_FindItemForAmmo( AMMO_BLASTER ));
00057 }

void Sentry_AttackDecision void   ) 
 

Definition at line 455 of file NPC_AI_Sentry.c.

References CHAN_AUTO, entityShared_t::currentOrigin, DistanceHorizontalSquared(), gentity_s::enemy, G_SoundIndex(), G_SoundOnEnt(), gentity_s::health, entityState_s::loopSound, MIN_DISTANCE_SQR, NPC, NPC_CheckEnemyExt(), NPC_ClearLOS4(), NPC_FaceEnemy(), NPCInfo, NULL, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, SCF_CHASE_ENEMIES, gNPC_t::scriptFlags, Sentry_Hunt(), Sentry_Idle(), Sentry_MaintainHeight(), Sentry_RangedAttack(), TIMER_Done(), TIMER_Set(), and va().

Referenced by NPC_BSSentry_Default().

00456 {
00457         float           distance;       
00458         qboolean        visible;
00459         qboolean        advance;
00460 
00461         // Always keep a good height off the ground
00462         Sentry_MaintainHeight();
00463 
00464         NPC->s.loopSound = G_SoundIndex( "sound/chars/sentry/misc/sentry_hover_2_lp" );
00465 
00466         //randomly talk
00467         if ( TIMER_Done(NPC,"patrolNoise") )
00468         {
00469                 if (TIMER_Done(NPC,"angerNoise"))
00470                 {
00471                         G_SoundOnEnt( NPC, CHAN_AUTO, va("sound/chars/sentry/misc/talk%d", Q_irand(1, 3)) );
00472 
00473                         TIMER_Set( NPC, "patrolNoise", Q_irand( 4000, 10000 ) );
00474                 }
00475         }
00476 
00477         // He's dead.
00478         if (NPC->enemy->health<1)
00479         {
00480                 NPC->enemy = NULL;
00481                 Sentry_Idle();
00482                 return;
00483         }
00484 
00485         // If we don't have an enemy, just idle
00486         if ( NPC_CheckEnemyExt(qfalse) == qfalse )
00487         {
00488                 Sentry_Idle();
00489                 return;
00490         }
00491 
00492         // Rate our distance to the target and visibilty
00493         distance        = (int) DistanceHorizontalSquared( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin ); 
00494         visible         = NPC_ClearLOS4( NPC->enemy );
00495         advance         = (qboolean)(distance > MIN_DISTANCE_SQR);
00496 
00497         // If we cannot see our target, move to see it
00498         if ( visible == qfalse )
00499         {
00500                 if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
00501                 {
00502                         Sentry_Hunt( visible, advance );
00503                         return;
00504                 }
00505         }
00506 
00507         NPC_FaceEnemy( qtrue );
00508 
00509         Sentry_RangedAttack( visible, advance );
00510 }

void Sentry_Fire void   ) 
 

Definition at line 112 of file NPC_AI_Sentry.c.

References AngleVectors(), gentity_s::attackDebounceTime, BOTH_ATTACK1, BOTH_POWERUP1, gNPC_t::burstCount, CHAN_AUTO, gentity_s::classname, gentity_s::clipmask, CONTENTS_LIGHTSABER, CreateMissile(), entityShared_t::currentAngles, entityShared_t::currentOrigin, gentity_s::damage, DAMAGE_DEATH_KNOCKBACK, gentity_s::dflags, FL_SHIELDED, gentity_s::flags, G_EffectIndex(), G_PlayEffectID(), G_Sound(), G_SoundIndex(), g_spskill, gentity_t, gentity_s::ghoul2, vmCvar_t::integer, level, gNPC_t::localState, LSTATE_ACTIVE, LSTATE_ATTACKING, LSTATE_POWERING_UP, MASK_SHOT, gentity_s::methodOfDeath, MOD_BRYAR_PISTOL, gentity_s::modelScale, NPC, NPC_SetAnim(), NPCInfo, NULL, ORIGIN, qfalse, gentity_s::r, gentity_s::s, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, level_locals_t::time, TIMER_Done(), TIMER_Set(), trap_G2API_AddBolt(), trap_G2API_GetBoltMatrix(), vec3_t, entityState_s::weapon, and WP_BRYAR_PISTOL.

Referenced by Sentry_RangedAttack().

00113 {
00114         vec3_t  muzzle;
00115         static  vec3_t  forward, vright, up;
00116         gentity_t       *missile;
00117         mdxaBone_t      boltMatrix;
00118         int                     bolt;
00119         int                     which;
00120 
00121         NPC->flags &= ~FL_SHIELDED;
00122 
00123         if ( NPCInfo->localState == LSTATE_POWERING_UP )
00124         {
00125                 if ( TIMER_Done( NPC, "powerup" ))
00126                 {
00127                         NPCInfo->localState = LSTATE_ATTACKING;
00128                         NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00129                 }
00130                 else
00131                 {
00132                         // can't do anything right now
00133                         return;
00134                 }
00135         }
00136         else if ( NPCInfo->localState == LSTATE_ACTIVE )
00137         {
00138                 NPCInfo->localState = LSTATE_POWERING_UP;
00139 
00140                 G_Sound( NPC, CHAN_AUTO, G_SoundIndex("sound/chars/sentry/misc/sentry_shield_open") );          
00141                 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_POWERUP1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00142                 TIMER_Set( NPC, "powerup", 250 );
00143                 return;
00144         }
00145         else if ( NPCInfo->localState != LSTATE_ATTACKING )
00146         {
00147                 // bad because we are uninitialized
00148                 NPCInfo->localState = LSTATE_ACTIVE;
00149                 return;
00150         }
00151 
00152         // Which muzzle to fire from?
00153         which = NPCInfo->burstCount % 3;
00154         switch( which )
00155         {
00156         case 0:
00157                 bolt = trap_G2API_AddBolt(NPC->ghoul2, 0, "*flash1");
00158                 break;
00159         case 1:
00160                 bolt = trap_G2API_AddBolt(NPC->ghoul2, 0, "*flash2");
00161                 break;
00162         case 2:
00163         default:
00164                 bolt = trap_G2API_AddBolt(NPC->ghoul2, 0, "*flash03");
00165         }
00166 
00167         trap_G2API_GetBoltMatrix( NPC->ghoul2, 0, 
00168                                 bolt,
00169                                 &boltMatrix, NPC->r.currentAngles, NPC->r.currentOrigin, level.time,
00170                                 NULL, NPC->modelScale );
00171 
00172         BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, muzzle );
00173 
00174         AngleVectors( NPC->r.currentAngles, forward, vright, up );
00175 //      G_Sound( NPC, G_SoundIndex("sound/chars/sentry/misc/shoot.wav"));
00176 
00177         G_PlayEffectID( G_EffectIndex("bryar/muzzle_flash"), muzzle, forward );
00178 
00179         missile = CreateMissile( muzzle, forward, 1600, 10000, NPC, qfalse );
00180 
00181         missile->classname = "bryar_proj";
00182         missile->s.weapon = WP_BRYAR_PISTOL;
00183 
00184         missile->dflags = DAMAGE_DEATH_KNOCKBACK;
00185         missile->methodOfDeath = MOD_BRYAR_PISTOL;
00186         missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
00187 
00188         NPCInfo->burstCount++;
00189         NPC->attackDebounceTime = level.time + 50;
00190         missile->damage = 5;
00191 
00192         // now scale for difficulty
00193         if ( g_spskill.integer == 0 )
00194         {
00195                 NPC->attackDebounceTime += 200;
00196                 missile->damage = 1;
00197         }
00198         else if ( g_spskill.integer == 1 )
00199         {
00200                 NPC->attackDebounceTime += 100;
00201                 missile->damage = 3;
00202         }
00203 }

void Sentry_Hunt qboolean  visible,
qboolean  advance
 

Definition at line 372 of file NPC_AI_Sentry.c.

References gentity_s::client, entityShared_t::currentOrigin, gentity_s::enemy, g_spskill, gNPC_t::goalEntity, gNPC_t::goalRadius, vmCvar_t::integer, level, NPC, NPC_GetMoveDirection(), NPCInfo, gclient_s::ps, qfalse, gentity_s::r, SENTRY_FORWARD_BASE_SPEED, SENTRY_FORWARD_MULTIPLIER, Sentry_Strafe(), gNPC_t::standTime, level_locals_t::time, vec3_t, VectorMA, VectorNormalize(), VectorSubtract, and playerState_s::velocity.

Referenced by Sentry_AttackDecision(), and Sentry_RangedAttack().

00373 {
00374         float   distance, speed;
00375         vec3_t  forward;
00376 
00377         //If we're not supposed to stand still, pursue the player
00378         if ( NPCInfo->standTime < level.time )
00379         {
00380                 // Only strafe when we can see the player
00381                 if ( visible )
00382                 {
00383                         Sentry_Strafe();
00384                         return;
00385                 }
00386         }
00387 
00388         //If we don't want to advance, stop here
00389         if ( !advance && visible )
00390                 return;
00391 
00392         //Only try and navigate if the player is visible
00393         if ( visible == qfalse )
00394         {
00395                 // Move towards our goal
00396                 NPCInfo->goalEntity = NPC->enemy;
00397                 NPCInfo->goalRadius = 12;
00398 
00399                 //Get our direction from the navigator if we can't see our target
00400                 if ( NPC_GetMoveDirection( forward, &distance ) == qfalse )
00401                         return;
00402         }
00403         else
00404         {
00405                 VectorSubtract( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, forward );
00406                 distance = VectorNormalize( forward );
00407         }
00408 
00409         speed = SENTRY_FORWARD_BASE_SPEED + SENTRY_FORWARD_MULTIPLIER * g_spskill.integer;
00410         VectorMA( NPC->client->ps.velocity, speed, forward, NPC->client->ps.velocity );
00411 }

void Sentry_Idle void   ) 
 

Definition at line 311 of file NPC_AI_Sentry.c.

References BOTH_SLEEP1, gNPC_t::burstCount, gentity_s::client, FL_SHIELDED, gentity_s::flags, gNPC_t::localState, LSTATE_WAKEUP, NPC, NPC_BSIdle(), NPC_SetAnim(), NPCInfo, gclient_s::ps, SCF_LOOK_FOR_ENEMIES, gNPC_t::scriptFlags, Sentry_MaintainHeight(), SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, and playerState_s::torsoTimer.

Referenced by NPC_BSSentry_Default(), and Sentry_AttackDecision().

00312 {
00313         Sentry_MaintainHeight();
00314 
00315         // Is he waking up?
00316         if (NPCInfo->localState == LSTATE_WAKEUP)
00317         {
00318                 if (NPC->client->ps.torsoTimer<=0)
00319                 {
00320                         NPCInfo->scriptFlags |= SCF_LOOK_FOR_ENEMIES;
00321                         NPCInfo->burstCount = 0;
00322                 }
00323         }
00324         else
00325         {
00326                 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_SLEEP1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00327                 NPC->flags |= FL_SHIELDED;
00328 
00329                 NPC_BSIdle();
00330         }
00331 }

void Sentry_MaintainHeight void   ) 
 

Definition at line 210 of file NPC_AI_Sentry.c.

References gentity_s::client, entityShared_t::currentOrigin, gentity_s::enemy, fabs(), G_SoundIndex(), gentity_t, gNPC_t::goalEntity, gNPC_t::lastGoalEntity, entityState_s::loopSound, entityShared_t::maxs, NPC, NPC_FaceEnemy(), NPC_UpdateAngles(), NPCInfo, NULL, gclient_s::ps, qtrue, gentity_s::r, gentity_s::s, SENTRY_HOVER_HEIGHT, SENTRY_VELOCITY_DECAY, ucmd, usercmd_s::upmove, and playerState_s::velocity.

Referenced by NPC_Sentry_Patrol(), Sentry_AttackDecision(), and Sentry_Idle().

00211 {       
00212         float   dif;
00213 
00214         NPC->s.loopSound = G_SoundIndex( "sound/chars/sentry/misc/sentry_hover_1_lp" );
00215 
00216         // Update our angles regardless
00217         NPC_UpdateAngles( qtrue, qtrue );
00218 
00219         // If we have an enemy, we should try to hover at about enemy eye level
00220         if ( NPC->enemy )
00221         {
00222                 // Find the height difference
00223                 dif = (NPC->enemy->r.currentOrigin[2]+NPC->enemy->r.maxs[2]) - NPC->r.currentOrigin[2]; 
00224 
00225                 // cap to prevent dramatic height shifts
00226                 if ( fabs( dif ) > 8 )
00227                 {
00228                         if ( fabs( dif ) > SENTRY_HOVER_HEIGHT )
00229                         {
00230                                 dif = ( dif < 0 ? -24 : 24 );
00231                         }
00232 
00233                         NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2;
00234                 }
00235         }
00236         else
00237         {
00238                 gentity_t *goal = NULL;
00239 
00240                 if ( NPCInfo->goalEntity )      // Is there a goal?
00241                 {
00242                         goal = NPCInfo->goalEntity;
00243                 }
00244                 else
00245                 {
00246                         goal = NPCInfo->lastGoalEntity;
00247                 }
00248 
00249                 if (goal)
00250                 {
00251                         dif = goal->r.currentOrigin[2] - NPC->r.currentOrigin[2];
00252 
00253                         if ( fabs( dif ) > SENTRY_HOVER_HEIGHT )
00254                         {
00255                                 ucmd.upmove = ( ucmd.upmove < 0 ? -4 : 4 );
00256                         }
00257                         else
00258                         {
00259                                 if ( NPC->client->ps.velocity[2] )
00260                                 {
00261                                         NPC->client->ps.velocity[2] *= SENTRY_VELOCITY_DECAY;
00262 
00263                                         if ( fabs( NPC->client->ps.velocity[2] ) < 2 )
00264                                         {
00265                                                 NPC->client->ps.velocity[2] = 0;
00266                                         }
00267                                 }
00268                         }
00269                 }
00270                 // Apply friction to Z
00271                 else if ( NPC->client->ps.velocity[2] )
00272                 {
00273                         NPC->client->ps.velocity[2] *= SENTRY_VELOCITY_DECAY;
00274 
00275                         if ( fabs( NPC->client->ps.velocity[2] ) < 1 )
00276                         {
00277                                 NPC->client->ps.velocity[2] = 0;
00278                         }
00279                 }
00280         }
00281 
00282         // Apply friction
00283         if ( NPC->client->ps.velocity[0] )
00284         {
00285                 NPC->client->ps.velocity[0] *= SENTRY_VELOCITY_DECAY;
00286 
00287                 if ( fabs( NPC->client->ps.velocity[0] ) < 1 )
00288                 {
00289                         NPC->client->ps.velocity[0] = 0;
00290                 }
00291         }
00292 
00293         if ( NPC->client->ps.velocity[1] )
00294         {
00295                 NPC->client->ps.velocity[1] *= SENTRY_VELOCITY_DECAY;
00296 
00297                 if ( fabs( NPC->client->ps.velocity[1] ) < 1 )
00298                 {
00299                         NPC->client->ps.velocity[1] = 0;
00300                 }
00301         }
00302 
00303         NPC_FaceEnemy( qtrue );
00304 }

void Sentry_RangedAttack qboolean  visible,
qboolean  advance
 

Definition at line 418 of file NPC_AI_Sentry.c.

References gentity_s::attackDebounceTime, BOTH_FLY_SHIELDED, gNPC_t::burstCount, CHAN_AUTO, FL_SHIELDED, gentity_s::flags, gentity_s::fly_sound_debounce_time, G_SoundOnEnt(), level, gNPC_t::localState, LSTATE_ACTIVE, NPC, NPC_SetAnim(), NPCInfo, Q_irand(), SCF_CHASE_ENEMIES, gNPC_t::scriptFlags, Sentry_Fire(), Sentry_Hunt(), SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, level_locals_t::time, TIMER_Done(), and TIMER_Set().

Referenced by Sentry_AttackDecision().

00419 {
00420         if ( TIMER_Done( NPC, "attackDelay" ) && NPC->attackDebounceTime < level.time && visible )      // Attack?
00421         {
00422                 if ( NPCInfo->burstCount > 6 )
00423                 {
00424                         if ( !NPC->fly_sound_debounce_time )
00425                         {//delay closing down to give the player an opening
00426                                 NPC->fly_sound_debounce_time = level.time + Q_irand( 500, 2000 );
00427                         }
00428                         else if ( NPC->fly_sound_debounce_time < level.time )
00429                         {
00430                                 NPCInfo->localState = LSTATE_ACTIVE;
00431                                 NPC->fly_sound_debounce_time = NPCInfo->burstCount = 0;
00432                                 TIMER_Set( NPC, "attackDelay", Q_irand( 2000, 3500) );
00433                                 NPC->flags |= FL_SHIELDED;
00434                                 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_FLY_SHIELDED, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00435                                 G_SoundOnEnt( NPC, CHAN_AUTO, "sound/chars/sentry/misc/sentry_shield_close" );
00436                         }
00437                 }
00438                 else
00439                 {
00440                         Sentry_Fire();
00441                 }
00442         }
00443 
00444         if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
00445         {
00446                 Sentry_Hunt( visible, advance );
00447         }
00448 }

void Sentry_Strafe void   ) 
 

Definition at line 338 of file NPC_AI_Sentry.c.

References AngleVectors(), gentity_s::client, entityShared_t::currentOrigin, renderInfo_s::eyeAngles, trace_t::fraction, level, MASK_SOLID, NPC, NPCInfo, NULL, entityState_s::number, gclient_s::ps, gentity_s::r, rand(), random, gclient_s::renderInfo, gentity_s::s, SENTRY_STRAFE_DIS, SENTRY_STRAFE_VEL, SENTRY_UPWARD_PUSH, gNPC_t::standTime, level_locals_t::time, trap_Trace(), vec3_t, VectorMA, and playerState_s::velocity.

Referenced by Sentry_Hunt().

00339 {
00340         int             dir;
00341         vec3_t  end, right;
00342         trace_t tr;
00343 
00344         AngleVectors( NPC->client->renderInfo.eyeAngles, NULL, right, NULL );
00345 
00346         // Pick a random strafe direction, then check to see if doing a strafe would be
00347         //      reasonable valid
00348         dir = ( rand() & 1 ) ? -1 : 1;
00349         VectorMA( NPC->r.currentOrigin, SENTRY_STRAFE_DIS * dir, right, end );
00350 
00351         trap_Trace( &tr, NPC->r.currentOrigin, NULL, NULL, end, NPC->s.number, MASK_SOLID );
00352 
00353         // Close enough
00354         if ( tr.fraction > 0.9f )
00355         {
00356                 VectorMA( NPC->client->ps.velocity, SENTRY_STRAFE_VEL * dir, right, NPC->client->ps.velocity );
00357 
00358                 // Add a slight upward push
00359                 NPC->client->ps.velocity[2] += SENTRY_UPWARD_PUSH;
00360 
00361                 // Set the strafe start time so we can do a controlled roll
00362         //      NPC->fx_time = level.time;
00363                 NPCInfo->standTime = level.time + 3000 + random() * 500;
00364         }
00365 }

void sentry_use gentity_t self,
gentity_t other,
gentity_t activator
 

Definition at line 64 of file NPC_AI_Sentry.c.

References BOTH_POWERUP1, BSET_USE, FL_SHIELDED, gentity_s::flags, G_ActivateBehavior(), gentity_t, gNPC_t::localState, LSTATE_ACTIVE, gentity_s::NPC, NPC_SetAnim(), SETANIM_BOTH, SETANIM_FLAG_HOLD, and SETANIM_FLAG_OVERRIDE.

Referenced by NPC_BSSentry_Default().

00065 {
00066         G_ActivateBehavior(self,BSET_USE);
00067 
00068         self->flags &= ~FL_SHIELDED;
00069         NPC_SetAnim( self, SETANIM_BOTH, BOTH_POWERUP1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00070 //      self->NPC->localState = LSTATE_WAKEUP;
00071         self->NPC->localState = LSTATE_ACTIVE;
00072 }