codemp/game/NPC_AI_Wampa.c File Reference

#include "b_local.h"
#include "g_nav.h"

Go to the source code of this file.

Defines

#define MIN_DISTANCE   48
#define MIN_DISTANCE_SQR   ( MIN_DISTANCE * MIN_DISTANCE )
#define MAX_DISTANCE   1024
#define MAX_DISTANCE_SQR   ( MAX_DISTANCE * MAX_DISTANCE )
#define LSTATE_CLEAR   0
#define LSTATE_WAITING   1

Functions

void Wampa_SetBolts (gentity_t *self)
void NPC_Wampa_Precache (void)
void Wampa_Idle (void)
qboolean Wampa_CheckRoar (gentity_t *self)
void Wampa_Patrol (void)
void Wampa_Move (qboolean visible)
void G_Knockdown (gentity_t *victim)
void G_Dismember (gentity_t *ent, gentity_t *enemy, vec3_t point, int limbType, float limbRollBase, float limbPitchBase, int deathAnim, qboolean postDeath)
int NPC_GetEntsNearBolt (int *radiusEnts, float radius, int boltIndex, vec3_t boltOrg)
void Wampa_Slash (int boltIndex, qboolean backhand)
void Wampa_Attack (float distance, qboolean doCharge)
void Wampa_Combat (void)
void NPC_Wampa_Pain (gentity_t *self, gentity_t *attacker, int damage)
void NPC_BSWampa_Default (void)

Variables

float enemyDist = 0


Define Documentation

#define LSTATE_CLEAR   0
 

Definition at line 11 of file NPC_AI_Wampa.c.

#define LSTATE_WAITING   1
 

Definition at line 12 of file NPC_AI_Wampa.c.

#define MAX_DISTANCE   1024
 

Definition at line 8 of file NPC_AI_Wampa.c.

#define MAX_DISTANCE_SQR   ( MAX_DISTANCE * MAX_DISTANCE )
 

Definition at line 9 of file NPC_AI_Wampa.c.

#define MIN_DISTANCE   48
 

Definition at line 5 of file NPC_AI_Wampa.c.

#define MIN_DISTANCE_SQR   ( MIN_DISTANCE * MIN_DISTANCE )
 

Definition at line 6 of file NPC_AI_Wampa.c.


Function Documentation

void G_Dismember gentity_t ent,
gentity_t enemy,
vec3_t  point,
int  limbType,
float  limbRollBase,
float  limbPitchBase,
int  deathAnim,
qboolean  postDeath
 

Definition at line 3311 of file g_combat.c.

References entityState_s::apos, BG_GetRootSurfNameWithVariant(), BG_InDeathAnim(), gentity_s::classname, gentity_s::client, gentity_s::clipmask, Com_sprintf(), entityShared_t::contents, CONTENTS_TRIGGER, entityShared_t::currentAngles, entityShared_t::currentOrigin, entityState_s::customRGBA, gentity_s::epGravFactor, gentity_s::epVelocity, ET_GENERAL, ET_NPC, entityState_s::eType, FRAMETIME, G2_MODEL_PART, G2_MODELPART_HEAD, G2_MODELPART_LARM, G2_MODELPART_LLEG, G2_MODELPART_RARM, G2_MODELPART_RHAND, G2_MODELPART_RLEG, G2_MODELPART_WAIST, entityState_s::g2radius, G_SetOrigin(), G_Spawn(), gentity_t, gentity_s::ghoul2, gclient_s::lastSaberBase_Always, gclient_s::lastSaberStorageTime, level, LimbThink(), LimbTouch(), MASK_SOLID, MAX_QPATH, entityShared_t::maxs, entityShared_t::mins, entityState_s::modelGhoul2, entityState_s::modelindex, gentity_s::nextthink, entityState_s::number, gclient_s::olderIsValid, gclient_s::olderSaberBase, entityState_s::otherEntityNum2, gentity_s::physicsObject, entityState_s::pos, gclient_s::ps, Q_irand(), Q_strncpyz(), qtrue, gentity_s::r, gentity_s::s, gentity_s::speed, SVF_USE_CURRENT_ORIGIN, entityShared_t::svFlags, gentity_s::think, level_locals_t::time, playerState_s::torsoAnim, playerState_s::torsoTimer, gentity_s::touch, trap_G2API_GetSurfaceRenderStatus(), trap_G2API_SetSurfaceOnOff(), trap_LinkEntity(), trajectory_t::trBase, trajectory_t::trDelta, vec3_t, VectorAdd, VectorClear, VectorCopy, VectorMA, VectorNormalize(), VectorScale, VectorSet, VectorSubtract, playerState_s::velocity, playerState_s::viewangles, playerState_s::weapon, entityState_s::weapon, and WP_SABER.

Referenced by DismembermentByNum(), DismembermentTest(), G_CheckForDismemberment(), Rancor_Attack(), Rancor_Bite(), and Wampa_Slash().

03312 {
03313         vec3_t  newPoint, dir, vel;
03314         gentity_t *limb;
03315         char    limbName[MAX_QPATH];
03316         char    stubName[MAX_QPATH];
03317         char    stubCapName[MAX_QPATH];
03318 
03319         if (limbType == G2_MODELPART_HEAD)
03320         {
03321                 Q_strncpyz( limbName , "head", sizeof( limbName  ) );
03322                 Q_strncpyz( stubCapName, "torso_cap_head", sizeof( stubCapName ) );
03323         }
03324         else if (limbType == G2_MODELPART_WAIST)
03325         {
03326                 Q_strncpyz( limbName, "torso", sizeof( limbName ) );
03327                 Q_strncpyz( stubCapName, "hips_cap_torso", sizeof( stubCapName ) );
03328         }
03329         else if (limbType == G2_MODELPART_LARM)
03330         {
03331                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "l_arm", limbName, sizeof(limbName) );
03332                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "torso", stubName, sizeof(stubName) );
03333                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_l_arm", stubName );
03334         }
03335         else if (limbType == G2_MODELPART_RARM)
03336         {
03337                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_arm", limbName, sizeof(limbName) );
03338                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "torso", stubName, sizeof(stubName) );
03339                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_arm", stubName );
03340         }
03341         else if (limbType == G2_MODELPART_RHAND)
03342         {
03343                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_hand", limbName, sizeof(limbName) );
03344                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_arm", stubName, sizeof(stubName) );
03345                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_hand", stubName );
03346         }
03347         else if (limbType == G2_MODELPART_LLEG)
03348         {
03349                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "l_leg", limbName, sizeof(limbName) );
03350                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "hips", stubName, sizeof(stubName) );
03351                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_l_leg", stubName );
03352         }
03353         else if (limbType == G2_MODELPART_RLEG)
03354         {
03355                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_leg", limbName, sizeof(limbName) );
03356                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "hips", stubName, sizeof(stubName) );
03357                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_leg", stubName );
03358         }
03359         else
03360         {//umm... just default to the right leg, I guess (same as on client)
03361                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "r_leg", limbName, sizeof(limbName) );
03362                 BG_GetRootSurfNameWithVariant( ent->ghoul2, "hips", stubName, sizeof(stubName) );
03363                 Com_sprintf( stubCapName, sizeof( stubCapName), "%s_cap_r_leg", stubName );
03364         }
03365 
03366         if (ent->ghoul2 && limbName && trap_G2API_GetSurfaceRenderStatus(ent->ghoul2, 0, limbName))
03367         { //is it already off? If so there's no reason to be doing it again, so get out of here.
03368                 return;
03369         }
03370 
03371         VectorCopy( point, newPoint );
03372         limb = G_Spawn();
03373         limb->classname = "playerlimb";
03374 
03375         /*
03376         if (limbType == G2_MODELPART_WAIST)
03377         { //slight hack
03378                 newPoint[2] += 1;
03379         }
03380         */
03381 
03382         G_SetOrigin( limb, newPoint );
03383         VectorCopy( newPoint, limb->s.pos.trBase );
03384         limb->think = LimbThink;
03385         limb->touch = LimbTouch;
03386         limb->speed = level.time + Q_irand(8000, 16000);
03387         limb->nextthink = level.time + FRAMETIME;
03388 
03389         limb->r.svFlags = SVF_USE_CURRENT_ORIGIN;
03390         limb->clipmask = MASK_SOLID;
03391         limb->r.contents = CONTENTS_TRIGGER;
03392         limb->physicsObject = qtrue;
03393         VectorSet( limb->r.mins, -6.0f, -6.0f, -3.0f );
03394         VectorSet( limb->r.maxs, 6.0f, 6.0f, 6.0f );
03395 
03396         limb->s.g2radius = 200;
03397 
03398         limb->s.eType = ET_GENERAL;
03399         limb->s.weapon = G2_MODEL_PART;
03400         limb->s.modelGhoul2 = limbType;
03401         limb->s.modelindex = ent->s.number;
03402         if (!ent->client)
03403         {
03404                 limb->s.modelindex = -1;
03405                 limb->s.otherEntityNum2 = ent->s.number;
03406         }
03407 
03408         VectorClear(limb->s.apos.trDelta);
03409 
03410         if (ent->client)
03411         {
03412                 VectorCopy(ent->client->ps.viewangles, limb->r.currentAngles);
03413                 VectorCopy(ent->client->ps.viewangles, limb->s.apos.trBase);
03414         }
03415         else
03416         {
03417                 VectorCopy(ent->r.currentAngles, limb->r.currentAngles);
03418                 VectorCopy(ent->r.currentAngles, limb->s.apos.trBase);
03419         }
03420 
03421         //Set up the ExPhys values for the entity.
03422         limb->epGravFactor = 0;
03423         VectorClear(limb->epVelocity);
03424         VectorSubtract( point, ent->r.currentOrigin, dir );
03425         VectorNormalize( dir );
03426         if (ent->client)
03427         {
03428                 VectorCopy(ent->client->ps.velocity, vel);
03429         }
03430         else
03431         {
03432                 VectorCopy(ent->s.pos.trDelta, vel);
03433         }
03434         VectorMA( vel, 80, dir, limb->epVelocity );
03435 
03436         //add some vertical velocity
03437         if (limbType == G2_MODELPART_HEAD ||
03438                 limbType == G2_MODELPART_WAIST)
03439         {
03440                 limb->epVelocity[2] += 10;
03441         }
03442 
03443         if (enemy && enemy->client && ent && ent != enemy && ent->s.number != enemy->s.number &&
03444                 enemy->client->ps.weapon == WP_SABER && enemy->client->olderIsValid &&
03445                 (level.time - enemy->client->lastSaberStorageTime) < 200)
03446         { //The enemy has valid saber positions between this and last frame. Use them to factor in direction of the limb.
03447                 vec3_t dif;
03448                 float totalDistance;
03449                 const float distScale = 1.2f;
03450 
03451                 //scale down the initial velocity first, which is based on the speed of the limb owner.
03452                 //ExPhys object velocity operates on a slightly different scale than Q3-based physics velocity.
03453                 VectorScale(limb->epVelocity, 0.4f, limb->epVelocity);
03454 
03455                 VectorSubtract(enemy->client->lastSaberBase_Always, enemy->client->olderSaberBase, dif);
03456                 totalDistance = VectorNormalize(dif);
03457 
03458                 VectorScale(dif, totalDistance*distScale, dif);
03459                 VectorAdd(limb->epVelocity, dif, limb->epVelocity);
03460 
03461                 if (ent->client && (ent->client->ps.torsoTimer > 0 || !BG_InDeathAnim(ent->client->ps.torsoAnim)))
03462                 { //if he's done with his death anim we don't actually want the limbs going far
03463                         vec3_t preVel;
03464 
03465                         VectorCopy(limb->epVelocity, preVel);
03466                         preVel[2] = 0;
03467                         totalDistance = VectorNormalize(preVel);
03468 
03469                         if (totalDistance < 40.0f)
03470                         {
03471                                 float mAmt = 40.0f;//60.0f/totalDistance;
03472 
03473                                 limb->epVelocity[0] = preVel[0]*mAmt;
03474                                 limb->epVelocity[1] = preVel[1]*mAmt;
03475                         }
03476                 }
03477                 else if (ent->client)
03478                 {
03479                         VectorScale(limb->epVelocity, 0.3f, limb->epVelocity);
03480                 }
03481         }
03482 
03483         if (ent->s.eType == ET_NPC && ent->ghoul2 && limbName && stubCapName)
03484         { //if it's an npc remove these surfs on the server too. For players we don't even care cause there's no further dismemberment after death.
03485                 trap_G2API_SetSurfaceOnOff(ent->ghoul2, limbName, 0x00000100);
03486                 trap_G2API_SetSurfaceOnOff(ent->ghoul2, stubCapName, 0);
03487         }
03488 
03489         limb->s.customRGBA[0] = ent->s.customRGBA[0];
03490         limb->s.customRGBA[1] = ent->s.customRGBA[1];
03491         limb->s.customRGBA[2] = ent->s.customRGBA[2];
03492         limb->s.customRGBA[3] = ent->s.customRGBA[3];
03493 
03494         trap_LinkEntity( limb );
03495 }

void G_Knockdown gentity_t victim  ) 
 

Definition at line 4327 of file g_combat.c.

04328 {
04329         if ( victim && victim->client && BG_KnockDownable(&victim->client->ps) )
04330         {
04331                 victim->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
04332                 victim->client->ps.forceDodgeAnim = 0;
04333                 victim->client->ps.forceHandExtendTime = level.time + 1100;
04334                 victim->client->ps.quickerGetup = qfalse;
04335         }
04336 }

void NPC_BSWampa_Default void   ) 
 

Definition at line 506 of file NPC_AI_Wampa.c.

References BS_DEFAULT, BS_SEARCH, BS_WANDER, BUTTON_WALKING, usercmd_s::buttons, CHAN_AUTO, CHAN_VOICE, CLASS_WAMPA, gentity_s::client, gNPC_t::confusionTime, entityShared_t::currentOrigin, EF2_USE_ALT_ANIM, playerState_s::eFlags2, gentity_s::enemy, enemyDist, G_SetEnemy(), G_Sound(), G_SoundIndex(), gentity_t, gNPC_t::homeWp, gentity_s::inuse, gentity_s::lastEnemy, level, NPC, NPC_BSSearch(), NPC_BSSearchStart(), NPC_BSWander(), NPC_CheckEnemy(), NPC_CheckEnemyExt(), gclient_s::NPC_class, NPC_FaceEnemy(), NPC_UpdateAngles(), NPCInfo, NULL, gclient_s::ps, Q_irand(), qfalse, qtrue, gentity_s::r, gentity_s::s, SCF_LOOK_FOR_ENEMIES, gNPC_t::scriptFlags, gentity_s::spawnflags, gNPC_t::tempBehavior, entityState_s::time, level_locals_t::time, TIMER_Done(), TIMER_Remove(), TIMER_Set(), ucmd, va(), ValidEnemy(), Wampa_Attack(), Wampa_CheckRoar(), Wampa_Combat(), Wampa_Idle(), Wampa_Patrol(), gentity_s::waypoint, and WAYPOINT_NONE.

Referenced by NPC_RunBehavior().

00507 {
00508         NPC->client->ps.eFlags2 &= ~EF2_USE_ALT_ANIM;
00509         //NORMAL ANIMS
00510         //      stand1 = normal stand
00511         //      walk1 = normal, non-angry walk
00512         //      walk2 = injured
00513         //      run1 = far away run
00514         //      run2 = close run
00515         //VICTIM ANIMS
00516         //      grabswipe = melee1 - sweep out and grab
00517         //      stand2 attack = attack4 - while holding victim, swipe at him
00518         //      walk3_drag = walk5 - walk with drag
00519         //      stand2 = hold victim
00520         //      stand2to1 = drop victim
00521         if ( !TIMER_Done( NPC, "rageTime" ) )
00522         {//do nothing but roar first time we see an enemy
00523                 NPC_FaceEnemy( qtrue );
00524                 return;
00525         }
00526         if ( NPC->enemy )
00527         {
00528                 if ( !TIMER_Done(NPC,"attacking") )
00529                 {//in middle of attack
00530                         //face enemy
00531                         NPC_FaceEnemy( qtrue );
00532                         //continue attack logic
00533                         enemyDist = Distance( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin );
00534                         Wampa_Attack( enemyDist, qfalse );
00535                         return;
00536                 }
00537                 else
00538                 {
00539                         if ( TIMER_Done(NPC,"angrynoise") )
00540                         {
00541                                 G_Sound( NPC, CHAN_VOICE, G_SoundIndex( va("sound/chars/wampa/misc/anger%d.wav", Q_irand(1, 2)) ) );
00542 
00543                                 TIMER_Set( NPC, "angrynoise", Q_irand( 5000, 10000 ) );
00544                         }
00545                         //else, if he's in our hand, we eat, else if he's on the ground, we keep attacking his dead body for a while
00546                         if( NPC->enemy->client && NPC->enemy->client->NPC_class == CLASS_WAMPA )
00547                         {//got mad at another Wampa, look for a valid enemy
00548                                 if ( TIMER_Done( NPC, "wampaInfight" ) )
00549                                 {
00550                                         NPC_CheckEnemyExt( qtrue );
00551                                 }
00552                         }
00553                         else
00554                         {
00555                                 if ( ValidEnemy( NPC->enemy ) == qfalse )
00556                                 {
00557                                         TIMER_Remove( NPC, "lookForNewEnemy" );//make them look again right now
00558                                         if ( !NPC->enemy->inuse || level.time - NPC->enemy->s.time > Q_irand( 10000, 15000 ) )
00559                                         {//it's been a while since the enemy died, or enemy is completely gone, get bored with him
00560                                                 NPC->enemy = NULL;
00561                                                 Wampa_Patrol();
00562                                                 NPC_UpdateAngles( qtrue, qtrue );
00563                                                 //just lost my enemy
00564                                                 if ( (NPC->spawnflags&2) )
00565                                                 {//search around me if I don't have an enemy
00566                                                         NPC_BSSearchStart( NPC->waypoint, BS_SEARCH );
00567                                                         NPCInfo->tempBehavior = BS_DEFAULT;
00568                                                 }
00569                                                 else if ( (NPC->spawnflags&1) )
00570                                                 {//wander if I don't have an enemy
00571                                                         NPC_BSSearchStart( NPC->waypoint, BS_WANDER );
00572                                                         NPCInfo->tempBehavior = BS_DEFAULT;
00573                                                 }
00574                                                 return;
00575                                         }
00576                                 }
00577                                 if ( TIMER_Done( NPC, "lookForNewEnemy" ) )
00578                                 {
00579                                         gentity_t *newEnemy, *sav_enemy = NPC->enemy;//FIXME: what about NPC->lastEnemy?
00580                                         NPC->enemy = NULL;
00581                                         newEnemy = NPC_CheckEnemy( NPCInfo->confusionTime < level.time, qfalse, qfalse );
00582                                         NPC->enemy = sav_enemy;
00583                                         if ( newEnemy && newEnemy != sav_enemy )
00584                                         {//picked up a new enemy!
00585                                                 NPC->lastEnemy = NPC->enemy;
00586                                                 G_SetEnemy( NPC, newEnemy );
00587                                                 //hold this one for at least 5-15 seconds
00588                                                 TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 5000, 15000 ) );
00589                                         }
00590                                         else
00591                                         {//look again in 2-5 secs
00592                                                 TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 2000, 5000 ) );
00593                                         }
00594                                 }
00595                         }
00596                         Wampa_Combat();
00597                         return;
00598                 }
00599         }
00600         else 
00601         {
00602                 if ( TIMER_Done(NPC,"idlenoise") )
00603                 {
00604                         G_Sound( NPC, CHAN_AUTO, G_SoundIndex( "sound/chars/wampa/misc/anger3.wav" ) );
00605 
00606                         TIMER_Set( NPC, "idlenoise", Q_irand( 2000, 4000 ) );
00607                 }
00608                 if ( (NPC->spawnflags&2) )
00609                 {//search around me if I don't have an enemy
00610                         if ( NPCInfo->homeWp == WAYPOINT_NONE )
00611                         {//no homewap, initialize the search behavior
00612                                 NPC_BSSearchStart( WAYPOINT_NONE, BS_SEARCH );
00613                                 NPCInfo->tempBehavior = BS_DEFAULT;
00614                         }
00615                         ucmd.buttons |= BUTTON_WALKING;
00616                         NPC_BSSearch();//this automatically looks for enemies
00617                 }
00618                 else if ( (NPC->spawnflags&1) )
00619                 {//wander if I don't have an enemy
00620                         if ( NPCInfo->homeWp == WAYPOINT_NONE )
00621                         {//no homewap, initialize the wander behavior
00622                                 NPC_BSSearchStart( WAYPOINT_NONE, BS_WANDER );
00623                                 NPCInfo->tempBehavior = BS_DEFAULT;
00624                         }
00625                         ucmd.buttons |= BUTTON_WALKING;
00626                         NPC_BSWander();
00627                         if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
00628                         {
00629                                 if ( NPC_CheckEnemyExt( qtrue ) == qfalse )
00630                                 {
00631                                         Wampa_Idle();
00632                                 }
00633                                 else
00634                                 {
00635                                         Wampa_CheckRoar( NPC );
00636                                         TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 5000, 15000 ) );
00637                                 }
00638                         }
00639                 }
00640                 else
00641                 {
00642                         if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
00643                         {
00644                                 Wampa_Patrol();
00645                         }
00646                         else
00647                         {
00648                                 Wampa_Idle();
00649                         }
00650                 }
00651         }
00652 
00653         NPC_UpdateAngles( qtrue, qtrue );
00654 }

int NPC_GetEntsNearBolt int *  radiusEnts,
float  radius,
int  boltIndex,
vec3_t  boltOrg
 

Definition at line 1761 of file NPC_utils.c.

References G_GetBoltPosition(), NPC, trap_EntitiesInBox(), vec3_t, and VectorCopy.

Referenced by Rancor_Bite(), Rancor_Smash(), Rancor_Swing(), and Wampa_Slash().

01762 {
01763         vec3_t          mins, maxs;
01764         int                     i;
01765 
01766         //get my handRBolt's position
01767         vec3_t  org;
01768 
01769         G_GetBoltPosition( NPC, boltIndex, org, 0 );
01770 
01771         VectorCopy( org, boltOrg );
01772 
01773         //Setup the bbox to search in
01774         for ( i = 0; i < 3; i++ )
01775         {
01776                 mins[i] = boltOrg[i] - radius;
01777                 maxs[i] = boltOrg[i] + radius;
01778         }
01779 
01780         //Get the number of entities in a given space
01781         return (trap_EntitiesInBox( mins, maxs, radiusEnts, 128 ));
01782 }

void NPC_Wampa_Pain gentity_t self,
gentity_t attacker,
int  damage
 

Definition at line 433 of file NPC_AI_Wampa.c.

References entityState_s::angles, BOTH_ATTACK1, BOTH_ATTACK2, BOTH_ATTACK3, BOTH_GESTURE1, BOTH_GESTURE2, BOTH_PAIN1, BOTH_PAIN2, CLASS_WAMPA, gentity_s::client, entityShared_t::currentOrigin, gentity_s::enemy, FL_NOTARGET, gentity_s::flags, G_SetEnemy(), gentity_t, gentity_s::health, gentity_s::inuse, gNPC_t::lastPathAngles, playerState_s::legsAnim, playerState_s::legsTimer, gNPC_t::localState, LSTATE_WAITING, gentity_s::NPC, gclient_s::NPC_class, NPC_SetAnim(), entityState_s::number, gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, gentity_s::s, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, TIMER_Done(), TIMER_Remove(), TIMER_Set(), VectorCopy, and Wampa_CheckRoar().

Referenced by NPC_PainFunc(), and NPC_SetMiscDefaultData().

00434 {
00435         qboolean hitByWampa = qfalse;
00436         if ( attacker&&attacker->client&&attacker->client->NPC_class==CLASS_WAMPA )
00437         {
00438                 hitByWampa = qtrue;
00439         }
00440         if ( attacker 
00441                 && attacker->inuse 
00442                 && attacker != self->enemy
00443                 && !(attacker->flags&FL_NOTARGET) )
00444         {
00445                 if ( (!attacker->s.number&&!Q_irand(0,3))
00446                         || !self->enemy
00447                         || self->enemy->health == 0
00448                         || (self->enemy->client&&self->enemy->client->NPC_class == CLASS_WAMPA)
00449                         || (!Q_irand(0, 4 ) && DistanceSquared( attacker->r.currentOrigin, self->r.currentOrigin ) < DistanceSquared( self->enemy->r.currentOrigin, self->r.currentOrigin )) ) 
00450                 {//if my enemy is dead (or attacked by player) and I'm not still holding/eating someone, turn on the attacker
00451                         //FIXME: if can't nav to my enemy, take this guy if I can nav to him
00452                         G_SetEnemy( self, attacker );
00453                         TIMER_Set( self, "lookForNewEnemy", Q_irand( 5000, 15000 ) );
00454                         if ( hitByWampa )
00455                         {//stay mad at this Wampa for 2-5 secs before looking for attacker enemies
00456                                 TIMER_Set( self, "wampaInfight", Q_irand( 2000, 5000 ) );
00457                         }
00458                 }
00459         }
00460         if ( (hitByWampa|| Q_irand( 0, 100 ) < damage )//hit by wampa, hit while holding live victim, or took a lot of damage
00461                 && self->client->ps.legsAnim != BOTH_GESTURE1
00462                 && self->client->ps.legsAnim != BOTH_GESTURE2
00463                 && TIMER_Done( self, "takingPain" ) )
00464         {
00465                 if ( !Wampa_CheckRoar( self ) )
00466                 {
00467                         if ( self->client->ps.legsAnim != BOTH_ATTACK1
00468                                 && self->client->ps.legsAnim != BOTH_ATTACK2
00469                                 && self->client->ps.legsAnim != BOTH_ATTACK3 )
00470                         {//cant interrupt one of the big attack anims
00471                                 if ( self->health > 100 || hitByWampa )
00472                                 {
00473                                         TIMER_Remove( self, "attacking" );
00474 
00475                                         VectorCopy( self->NPC->lastPathAngles, self->s.angles );
00476 
00477                                         if ( !Q_irand( 0, 1 ) )
00478                                         {
00479                                                 NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00480                                         }
00481                                         else
00482                                         {
00483                                                 NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00484                                         }
00485                                         TIMER_Set( self, "takingPain", self->client->ps.legsTimer+Q_irand(0, 500) );
00486                                         //allow us to re-evaluate our running speed/anim
00487                                         TIMER_Set( self, "runfar", -1 );
00488                                         TIMER_Set( self, "runclose", -1 );
00489                                         TIMER_Set( self, "walk", -1 );
00490 
00491                                         if ( self->NPC )
00492                                         {
00493                                                 self->NPC->localState = LSTATE_WAITING;
00494                                         }
00495                                 }
00496                         }
00497                 }
00498         }
00499 }

void NPC_Wampa_Precache void   ) 
 

Definition at line 43 of file NPC_AI_Wampa.c.

References G_SoundIndex().

Referenced by NPC_SpawnType(), and SP_NPC_Monster_Wampa().

00044 {
00045         /*
00046         int i;
00047         for ( i = 1; i < 4; i ++ )
00048         {
00049                 G_SoundIndex( va("sound/chars/wampa/growl%d.wav", i) );
00050         }
00051         for ( i = 1; i < 3; i ++ )
00052         {
00053                 G_SoundIndex( va("sound/chars/wampa/snort%d.wav", i) );
00054         }
00055         */
00056         G_SoundIndex( "sound/chars/rancor/swipehit.wav" );
00057         //G_SoundIndex( "sound/chars/wampa/chomp.wav" );
00058 }

void Wampa_Attack float  distance,
qboolean  doCharge
 

Definition at line 267 of file NPC_AI_Wampa.c.

References AngleVectors(), BOTH_ATTACK1, BOTH_ATTACK2, BOTH_ATTACK3, BUTTON_WALKING, usercmd_s::buttons, gentity_s::client, ENTITYNUM_NONE, playerState_s::groundEntityNum, renderInfo_s::handLBolt, renderInfo_s::handRBolt, playerState_s::legsAnim, playerState_s::legsTimer, entityShared_t::maxs, MIN_DISTANCE, NPC, NPC_SetAnim(), NULL, gclient_s::ps, Q_irand(), qfalse, qtrue, gentity_s::r, random, gclient_s::renderInfo, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, TIMER_Done2(), TIMER_Exists(), TIMER_Set(), ucmd, vec3_t, VectorScale, VectorSet, playerState_s::velocity, playerState_s::viewangles, Wampa_Move(), Wampa_Slash(), and YAW.

Referenced by NPC_BSWampa_Default(), and Wampa_Combat().

00268 {
00269         if ( !TIMER_Exists( NPC, "attacking" ) )
00270         {
00271                 if ( Q_irand(0, 2) && !doCharge )
00272                 {//double slash
00273                         NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00274                         TIMER_Set( NPC, "attack_dmg", 750 );
00275                 }
00276                 else if ( doCharge || (distance > 270 && distance < 430 && !Q_irand(0, 1)) )
00277                 {//leap
00278                         vec3_t  fwd, yawAng;
00279                         VectorSet( yawAng, 0, NPC->client->ps.viewangles[YAW], 0 );
00280                         NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00281                         TIMER_Set( NPC, "attack_dmg", 500 );
00282                         AngleVectors( yawAng, fwd, NULL, NULL );
00283                         VectorScale( fwd, distance*1.5f, NPC->client->ps.velocity );
00284                         NPC->client->ps.velocity[2] = 150;
00285                         NPC->client->ps.groundEntityNum = ENTITYNUM_NONE;
00286                 }
00287                 else
00288                 {//backhand
00289                         NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK3, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00290                         TIMER_Set( NPC, "attack_dmg", 250 );
00291                 }
00292 
00293                 TIMER_Set( NPC, "attacking", NPC->client->ps.legsTimer + random() * 200 );
00294                 //allow us to re-evaluate our running speed/anim
00295                 TIMER_Set( NPC, "runfar", -1 );
00296                 TIMER_Set( NPC, "runclose", -1 );
00297                 TIMER_Set( NPC, "walk", -1 );
00298         }
00299 
00300         // Need to do delayed damage since the attack animations encapsulate multiple mini-attacks
00301 
00302         if ( TIMER_Done2( NPC, "attack_dmg", qtrue ) )
00303         {
00304                 switch ( NPC->client->ps.legsAnim )
00305                 {
00306                 case BOTH_ATTACK1:
00307                         Wampa_Slash( NPC->client->renderInfo.handRBolt, qfalse );
00308                         //do second hit
00309                         TIMER_Set( NPC, "attack_dmg2", 100 );
00310                         break;
00311                 case BOTH_ATTACK2:
00312                         Wampa_Slash( NPC->client->renderInfo.handRBolt, qfalse );
00313                         TIMER_Set( NPC, "attack_dmg2", 100 );
00314                         break;
00315                 case BOTH_ATTACK3:
00316                         Wampa_Slash( NPC->client->renderInfo.handLBolt, qtrue );
00317                         break;
00318                 }
00319         }
00320         else if ( TIMER_Done2( NPC, "attack_dmg2", qtrue ) )
00321         {
00322                 switch ( NPC->client->ps.legsAnim )
00323                 {
00324                 case BOTH_ATTACK1:
00325                         Wampa_Slash( NPC->client->renderInfo.handLBolt, qfalse );
00326                         break;
00327                 case BOTH_ATTACK2:
00328                         Wampa_Slash( NPC->client->renderInfo.handLBolt, qfalse );
00329                         break;
00330                 }
00331         }
00332 
00333         // Just using this to remove the attacking flag at the right time
00334         TIMER_Done2( NPC, "attacking", qtrue );
00335 
00336         if ( NPC->client->ps.legsAnim == BOTH_ATTACK1 && distance > (NPC->r.maxs[0]+MIN_DISTANCE) )
00337         {//okay to keep moving
00338                 ucmd.buttons |= BUTTON_WALKING;
00339                 Wampa_Move( 1 );
00340         }
00341 }

qboolean Wampa_CheckRoar gentity_t self  ) 
 

Definition at line 78 of file NPC_AI_Wampa.c.

References BOTH_GESTURE1, BOTH_GESTURE2, gentity_s::client, gentity_t, playerState_s::legsTimer, level, NPC_SetAnim(), gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, level_locals_t::time, TIMER_Set(), and gentity_s::wait.

Referenced by NPC_BSWampa_Default(), NPC_Wampa_Pain(), Wampa_Combat(), and Wampa_Patrol().

00079 {
00080         if ( self->wait < level.time )
00081         {
00082                 self->wait = level.time + Q_irand( 5000, 20000 );
00083                 NPC_SetAnim( self, SETANIM_BOTH, Q_irand(BOTH_GESTURE1,BOTH_GESTURE2), (SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD) );
00084                 TIMER_Set( self, "rageTime", self->client->ps.legsTimer );
00085                 return qtrue;
00086         }
00087         return qfalse;
00088 }

void Wampa_Combat void   ) 
 

Definition at line 344 of file NPC_AI_Wampa.c.

References gNPC_t::combatMove, entityShared_t::currentAngles, entityShared_t::currentOrigin, gentity_s::enemy, enemyDist, fabs(), gNPC_t::goalEntity, gNPC_t::goalRadius, gentity_s::health, InFOV3(), gNPC_t::localState, LSTATE_CLEAR, LSTATE_WAITING, MAX_DISTANCE, entityShared_t::maxs, MIN_DISTANCE, NPC, NPC_ClearLOS(), NPC_FaceEnemy(), NPCInfo, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, TIMER_Done(), TIMER_Done2(), UpdateGoal(), vec3_t, VectorSet, Wampa_Attack(), Wampa_CheckRoar(), Wampa_Move(), and YAW.

Referenced by NPC_BSWampa_Default().

00345 {
00346         // If we cannot see our target or we have somewhere to go, then do that
00347         if ( !NPC_ClearLOS( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin ) )
00348         {
00349                 if ( !Q_irand( 0, 10 ) )
00350                 {
00351                         if ( Wampa_CheckRoar( NPC ) )
00352                         {
00353                                 return;
00354                         }
00355                 }
00356                 NPCInfo->combatMove = qtrue;
00357                 NPCInfo->goalEntity = NPC->enemy;
00358                 NPCInfo->goalRadius = MAX_DISTANCE;     // just get us within combat range
00359 
00360                 Wampa_Move( 0 );
00361                 return;
00362         }
00363         else if ( UpdateGoal() )
00364         {
00365                 NPCInfo->combatMove = qtrue;
00366                 NPCInfo->goalEntity = NPC->enemy;
00367                 NPCInfo->goalRadius = MAX_DISTANCE;     // just get us within combat range
00368 
00369                 Wampa_Move( 1 );
00370                 return;
00371         }
00372         else
00373         {
00374                 float           distance = enemyDist = Distance( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin );   
00375                 qboolean        advance = (qboolean)( distance > (NPC->r.maxs[0]+MIN_DISTANCE) ? qtrue : qfalse  );
00376                 qboolean        doCharge = qfalse;
00377 
00378                 // Sometimes I have problems with facing the enemy I'm attacking, so force the issue so I don't look dumb
00379                 //FIXME: always seems to face off to the left or right?!!!!
00380                 NPC_FaceEnemy( qtrue );
00381 
00382 
00383                 if ( advance )
00384                 {//have to get closer
00385                         vec3_t  yawOnlyAngles;
00386                         VectorSet( yawOnlyAngles, 0, NPC->r.currentAngles[YAW], 0 );
00387                         if ( NPC->enemy->health > 0//enemy still alive
00388                                 && fabs(distance-350) <= 80 //enemy anywhere from 270 to 430 away
00389                                 && InFOV3( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, yawOnlyAngles, 20, 20 ) )//enemy generally in front
00390                         {//10% chance of doing charge anim
00391                                 if ( !Q_irand( 0, 9 ) )
00392                                 {//go for the charge
00393                                         doCharge = qtrue;
00394                                         advance = qfalse;
00395                                 }
00396                         }
00397                 }
00398 
00399                 if (( advance || NPCInfo->localState == LSTATE_WAITING ) && TIMER_Done( NPC, "attacking" )) // waiting monsters can't attack
00400                 {
00401                         if ( TIMER_Done2( NPC, "takingPain", qtrue ))
00402                         {
00403                                 NPCInfo->localState = LSTATE_CLEAR;
00404                         }
00405                         else
00406                         {
00407                                 Wampa_Move( 1 );
00408                         }
00409                 }
00410                 else
00411                 {
00412                         if ( !Q_irand( 0, 20 ) )
00413                         {//FIXME: only do this if we just damaged them or vice-versa?
00414                                 if ( Wampa_CheckRoar( NPC ) )
00415                                 {
00416                                         return;
00417                                 }
00418                         }
00419                         if ( !Q_irand( 0, 1 ) )
00420                         {//FIXME: base on skill
00421                                 Wampa_Attack( distance, doCharge );
00422                         }
00423                 }
00424         }
00425 }

void Wampa_Idle void   ) 
 

Definition at line 66 of file NPC_AI_Wampa.c.

References BUTTON_WALKING, usercmd_s::buttons, gNPC_t::localState, LSTATE_CLEAR, NPC_MoveToGoal(), NPCInfo, qtrue, ucmd, and UpdateGoal().

Referenced by NPC_BSWampa_Default(), and Wampa_Patrol().

00067 {
00068         NPCInfo->localState = LSTATE_CLEAR;
00069 
00070         //If we have somewhere to go, then do that
00071         if ( UpdateGoal() )
00072         {
00073                 ucmd.buttons &= ~BUTTON_WALKING;
00074                 NPC_MoveToGoal( qtrue );
00075         }
00076 }

void Wampa_Move qboolean  visible  ) 
 

Definition at line 126 of file NPC_AI_Wampa.c.

References BUTTON_WALKING, usercmd_s::buttons, gentity_s::client, EF2_USE_ALT_ANIM, playerState_s::eFlags2, gentity_s::enemy, enemyDist, gNPC_t::goalEntity, gNPC_t::goalRadius, gNPC_t::localState, LSTATE_WAITING, MAX_DISTANCE, NPC, NPC_MoveToGoal(), NPCInfo, gclient_s::ps, Q_irand(), qtrue, gNPCstats_e::runSpeed, gNPC_t::stats, TIMER_Done(), TIMER_Set(), and ucmd.

Referenced by Wampa_Attack(), and Wampa_Combat().

00127 {
00128         if ( NPCInfo->localState != LSTATE_WAITING )
00129         {
00130                 NPCInfo->goalEntity = NPC->enemy;
00131 
00132                 if ( NPC->enemy )
00133                 {//pick correct movement speed and anim
00134                         //run by default
00135                         ucmd.buttons &= ~BUTTON_WALKING;
00136                         if ( !TIMER_Done( NPC, "runfar" ) 
00137                                 || !TIMER_Done( NPC, "runclose" ) )
00138                         {//keep running with this anim & speed for a bit
00139                         }
00140                         else if ( !TIMER_Done( NPC, "walk" ) )
00141                         {//keep walking for a bit
00142                                 ucmd.buttons |= BUTTON_WALKING;
00143                         }
00144                         else if ( visible && enemyDist > 384 && NPCInfo->stats.runSpeed == 180 )
00145                         {//fast run, all fours
00146                                 NPCInfo->stats.runSpeed = 300;
00147                                 TIMER_Set( NPC, "runfar", Q_irand( 2000, 4000 ) );
00148                         }
00149                         else if ( enemyDist > 256 && NPCInfo->stats.runSpeed == 300 )
00150                         {//slow run, upright
00151                                 NPCInfo->stats.runSpeed = 180;
00152                                 TIMER_Set( NPC, "runclose", Q_irand( 3000, 5000 ) );
00153                         }
00154                         else if ( enemyDist < 128 )
00155                         {//walk
00156                                 NPCInfo->stats.runSpeed = 180;
00157                                 ucmd.buttons |= BUTTON_WALKING;
00158                                 TIMER_Set( NPC, "walk", Q_irand( 4000, 6000 ) );
00159                         }
00160                 }
00161 
00162                 if ( NPCInfo->stats.runSpeed == 300 )
00163                 {//need to use the alternate run - hunched over on all fours
00164                         NPC->client->ps.eFlags2 |= EF2_USE_ALT_ANIM;
00165                 }
00166                 NPC_MoveToGoal( qtrue );
00167                 NPCInfo->goalRadius = MAX_DISTANCE;     // just get us within combat range
00168         }
00169 }

void Wampa_Patrol void   ) 
 

Definition at line 94 of file NPC_AI_Wampa.c.

References BUTTON_WALKING, usercmd_s::buttons, crandom, gNPC_t::localState, LSTATE_CLEAR, NPC, NPC_CheckEnemyExt(), NPC_MoveToGoal(), NPCInfo, Q_irand(), qfalse, qtrue, TIMER_Done(), TIMER_Set(), ucmd, UpdateGoal(), Wampa_CheckRoar(), and Wampa_Idle().

Referenced by NPC_BSWampa_Default().

00095 {
00096         NPCInfo->localState = LSTATE_CLEAR;
00097 
00098         //If we have somewhere to go, then do that
00099         if ( UpdateGoal() )
00100         {
00101                 ucmd.buttons |= BUTTON_WALKING;
00102                 NPC_MoveToGoal( qtrue );
00103         }
00104         else
00105         {
00106                 if ( TIMER_Done( NPC, "patrolTime" ))
00107                 {
00108                         TIMER_Set( NPC, "patrolTime", crandom() * 5000 + 5000 );
00109                 }
00110         }
00111 
00112         if ( NPC_CheckEnemyExt( qtrue ) == qfalse )
00113         {
00114                 Wampa_Idle();
00115                 return;
00116         }
00117         Wampa_CheckRoar( NPC );
00118         TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 5000, 15000 ) );
00119 }

void Wampa_SetBolts gentity_t self  ) 
 

Definition at line 16 of file NPC_AI_Wampa.c.

References gentity_s::client, renderInfo_s::crotchBolt, renderInfo_s::footLBolt, renderInfo_s::footRBolt, gentity_t, gentity_s::ghoul2, renderInfo_s::handLBolt, renderInfo_s::handRBolt, renderInfo_s::headBolt, gclient_s::renderInfo, renderInfo_t, renderInfo_s::torsoBolt, and trap_G2API_AddBolt().

Referenced by NPC_SetMiscDefaultData().

00017 {
00018         if ( self && self->client )
00019         {
00020                 renderInfo_t *ri = &self->client->renderInfo;
00021                 ri->headBolt = trap_G2API_AddBolt(self->ghoul2, 0, "*head_eyes");
00022                 //ri->cervicalBolt = trap_G2API_AddBolt(self->ghoul2, 0, "neck_bone" );
00023                 //ri->chestBolt = trap_G2API_AddBolt(self->ghoul2, 0, "upper_spine");
00024                 //ri->gutBolt = trap_G2API_AddBolt(self->ghoul2, 0, "mid_spine");
00025                 ri->torsoBolt = trap_G2API_AddBolt(self->ghoul2, 0, "lower_spine");
00026                 ri->crotchBolt = trap_G2API_AddBolt(self->ghoul2, 0, "rear_bone");
00027                 //ri->elbowLBolt = trap_G2API_AddBolt(self->ghoul2, 0, "*l_arm_elbow");
00028                 //ri->elbowRBolt = trap_G2API_AddBolt(self->ghoul2, 0, "*r_arm_elbow");
00029                 ri->handLBolt = trap_G2API_AddBolt(self->ghoul2, 0, "*l_hand");
00030                 ri->handRBolt = trap_G2API_AddBolt(self->ghoul2, 0, "*r_hand");
00031                 //ri->kneeLBolt = trap_G2API_AddBolt(self->ghoul2, 0, "*hips_l_knee");
00032                 //ri->kneeRBolt = trap_G2API_AddBolt(self->ghoul2, 0, "*hips_r_knee");
00033                 ri->footLBolt = trap_G2API_AddBolt(self->ghoul2, 0, "*l_leg_foot");
00034                 ri->footRBolt = trap_G2API_AddBolt(self->ghoul2, 0, "*r_leg_foot");
00035         }
00036 }

void Wampa_Slash int  boltIndex,
qboolean  backhand
 

Definition at line 177 of file NPC_AI_Wampa.c.

References AngleVectors(), BG_KnockDownable(), BOTH_DEATH17, BOTH_DEATHBACKWARD2, CHAN_WEAPON, CLASS_ATST, CLASS_RANCOR, CLASS_WAMPA, gentity_s::client, entityShared_t::currentOrigin, DAMAGE_NO_ARMOR, DAMAGE_NO_KNOCKBACK, flrand(), playerState_s::forceDodgeAnim, playerState_s::forceHandExtend, playerState_s::forceHandExtendTime, G2_MODELPART_HEAD, G2_MODELPART_RLEG, G2_MODELPART_WAIST, G_Damage(), G_Dismember(), g_entities, G_Knockdown(), G_Sound(), G_SoundIndex(), G_Throw(), gentity_t, HANDEXTEND_KNOCKDOWN, gentity_s::health, gentity_s::inuse, level, MOD_MELEE, NPC, gclient_s::NPC_class, NPC_GetEntsNearBolt(), NPC_SetAnim(), NULL, PITCH, gclient_s::ps, Q_irand(), qfalse, qtrue, playerState_s::quickerGetup, gentity_s::r, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, level_locals_t::time, playerState_s::torsoAnim, vec3_origin, vec3_t, VectorCopy, playerState_s::viewangles, and YAW.

Referenced by Wampa_Attack().

00178 {
00179         int                     radiusEntNums[128];
00180         int                     numEnts;
00181         const float     radius = 88;
00182         const float     radiusSquared = (radius*radius);
00183         int                     i;
00184         vec3_t          boltOrg;
00185         int                     damage = (backhand)?Q_irand(10,15):Q_irand(20,30);
00186 
00187         numEnts = NPC_GetEntsNearBolt( radiusEntNums, radius, boltIndex, boltOrg );
00188 
00189         for ( i = 0; i < numEnts; i++ )
00190         {
00191                 gentity_t *radiusEnt = &g_entities[radiusEntNums[i]];
00192                 if ( !radiusEnt->inuse )
00193                 {
00194                         continue;
00195                 }
00196                 
00197                 if ( radiusEnt == NPC )
00198                 {//Skip the wampa ent
00199                         continue;
00200                 }
00201                 
00202                 if ( radiusEnt->client == NULL )
00203                 {//must be a client
00204                         continue;
00205                 }
00206 
00207                 if ( DistanceSquared( radiusEnt->r.currentOrigin, boltOrg ) <= radiusSquared )
00208                 {
00209                         //smack
00210                         G_Damage( radiusEnt, NPC, NPC, vec3_origin, radiusEnt->r.currentOrigin, damage, ((backhand)?DAMAGE_NO_ARMOR:(DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK)), MOD_MELEE );
00211                         if ( backhand )
00212                         {
00213                                 //actually push the enemy
00214                                 vec3_t pushDir;
00215                                 vec3_t angs;
00216                                 VectorCopy( NPC->client->ps.viewangles, angs );
00217                                 angs[YAW] += flrand( 25, 50 );
00218                                 angs[PITCH] = flrand( -25, -15 );
00219                                 AngleVectors( angs, pushDir, NULL, NULL );
00220                                 if ( radiusEnt->client->NPC_class != CLASS_WAMPA
00221                                         && radiusEnt->client->NPC_class != CLASS_RANCOR
00222                                         && radiusEnt->client->NPC_class != CLASS_ATST )
00223                                 {
00224                                         G_Throw( radiusEnt, pushDir, 65 );
00225                                         if ( BG_KnockDownable(&radiusEnt->client->ps) &&
00226                                                 radiusEnt->health > 0 && Q_irand( 0, 1 ) )
00227                                         {//do pain on enemy
00228                                                 radiusEnt->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
00229                                                 radiusEnt->client->ps.forceDodgeAnim = 0;
00230                                                 radiusEnt->client->ps.forceHandExtendTime = level.time + 1100;
00231                                                 radiusEnt->client->ps.quickerGetup = qfalse;
00232                                         }
00233                                 }
00234                         }
00235                         else if ( radiusEnt->health <= 0 && radiusEnt->client )
00236                         {//killed them, chance of dismembering
00237                                 if ( !Q_irand( 0, 1 ) )
00238                                 {//bite something off
00239                                         int hitLoc = Q_irand( G2_MODELPART_HEAD, G2_MODELPART_RLEG );
00240                                         if ( hitLoc == G2_MODELPART_HEAD )
00241                                         {
00242                                                 NPC_SetAnim( radiusEnt, SETANIM_BOTH, BOTH_DEATH17, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00243                                         }
00244                                         else if ( hitLoc == G2_MODELPART_WAIST )
00245                                         {
00246                                                 NPC_SetAnim( radiusEnt, SETANIM_BOTH, BOTH_DEATHBACKWARD2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00247                                         }
00248                                         G_Dismember( radiusEnt, NPC, radiusEnt->r.currentOrigin, hitLoc, 90, 0, radiusEnt->client->ps.torsoAnim, qtrue);
00249                                 }
00250                         }
00251                         else if ( !Q_irand( 0, 3 ) && radiusEnt->health > 0 )
00252                         {//one out of every 4 normal hits does a knockdown, too
00253                                 vec3_t pushDir;
00254                                 vec3_t angs;
00255                                 VectorCopy( NPC->client->ps.viewangles, angs );
00256                                 angs[YAW] += flrand( 25, 50 );
00257                                 angs[PITCH] = flrand( -25, -15 );
00258                                 AngleVectors( angs, pushDir, NULL, NULL );
00259                                 G_Knockdown( radiusEnt );
00260                         }
00261                         G_Sound( radiusEnt, CHAN_WEAPON, G_SoundIndex( "sound/chars/rancor/swipehit.wav" ) );
00262                 }
00263         }
00264 }


Variable Documentation

float enemyDist = 0
 

Definition at line 14 of file NPC_AI_Wampa.c.

Referenced by Boba_FireDecide(), NPC_BSHuntAndKill(), NPC_BSWampa_Default(), turret_base_think(), turretG2_base_think(), VEH_TurretThink(), Wampa_Combat(), and Wampa_Move().