codemp/game/NPC_AI_Rancor.c File Reference

#include "g_headers.h"
#include "b_local.h"

Go to the source code of this file.

Defines

#define MIN_DISTANCE   128
#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 G_GetBoltPosition (gentity_t *self, int boltIndex, vec3_t pos, int modelIndex)
void Rancor_SetBolts (gentity_t *self)
void NPC_Rancor_Precache (void)
void Rancor_Idle (void)
qboolean Rancor_CheckRoar (gentity_t *self)
void Rancor_Patrol (void)
void Rancor_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)
float NPC_EntRangeFromBolt (gentity_t *targEnt, int boltIndex)
int NPC_GetEntsNearBolt (int *radiusEnts, float radius, int boltIndex, vec3_t boltOrg)
void Rancor_DropVictim (gentity_t *self)
void Rancor_Swing (qboolean tryGrab)
void Rancor_Smash (void)
void Rancor_Bite (void)
void TossClientItems (gentity_t *self)
void Rancor_Attack (float distance, qboolean doCharge)
void Rancor_Combat (void)
void NPC_Rancor_Pain (gentity_t *self, gentity_t *attacker, int damage)
void Rancor_CheckDropVictim (void)
void Rancor_Crush (void)
void NPC_BSRancor_Default (void)


Define Documentation

#define LSTATE_CLEAR   0
 

Definition at line 16 of file NPC_AI_Rancor.c.

#define LSTATE_WAITING   1
 

Definition at line 17 of file NPC_AI_Rancor.c.

#define MAX_DISTANCE   1024
 

Definition at line 13 of file NPC_AI_Rancor.c.

#define MAX_DISTANCE_SQR   ( MAX_DISTANCE * MAX_DISTANCE )
 

Definition at line 14 of file NPC_AI_Rancor.c.

#define MIN_DISTANCE   128
 

Definition at line 10 of file NPC_AI_Rancor.c.

#define MIN_DISTANCE_SQR   ( MIN_DISTANCE * MIN_DISTANCE )
 

Definition at line 11 of file NPC_AI_Rancor.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.

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_GetBoltPosition gentity_t self,
int  boltIndex,
vec3_t  pos,
int  modelIndex
 

Definition at line 1707 of file NPC_utils.c.

01708 {
01709         mdxaBone_t      boltMatrix;
01710         vec3_t          result, angles;
01711         
01712         if (!self || !self->inuse)
01713         {
01714                 return;
01715         }
01716 
01717         if (self->client)
01718         { //clients don't actually even keep r.currentAngles maintained
01719                 VectorSet(angles, 0, self->client->ps.viewangles[YAW], 0);
01720         }
01721         else
01722         {
01723                 VectorSet(angles, 0, self->r.currentAngles[YAW], 0);
01724         }
01725 
01726         if (  !self->ghoul2 )
01727         {
01728                 return;
01729         }
01730 
01731         trap_G2API_GetBoltMatrix( self->ghoul2, modelIndex, 
01732                                 boltIndex,
01733                                 &boltMatrix, angles, self->r.currentOrigin, level.time,
01734                                 NULL, self->modelScale );
01735         if ( pos )
01736         {
01737                 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, result );
01738                 VectorCopy( result, pos );
01739         }
01740 }

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_BSRancor_Default void   ) 
 

Definition at line 828 of file NPC_AI_Rancor.c.

References gentity_s::activator, AddSightEvent(), AddSoundEvent(), AEL_DANGER, AEL_DANGER_GREAT, BOTH_ATTACK3, BOTH_PAIN2, CHAN_AUTO, CLASS_RANCOR, gentity_s::client, gNPC_t::confusionTime, gentity_s::count, entityShared_t::currentOrigin, EF2_GENERIC_NPC_FLAG, EF2_USE_ALT_ANIM, playerState_s::eFlags2, gentity_s::enemy, G_SetEnemy(), G_Sound(), G_SoundIndex(), gentity_t, gentity_s::inuse, gentity_s::lastEnemy, playerState_s::legsAnim, level, NPC, NPC_CheckEnemy(), NPC_CheckEnemyExt(), gclient_s::NPC_class, NPC_FaceEnemy(), NPC_UpdateAngles(), NPCInfo, NULL, gclient_s::ps, Q_irand(), qfalse, qtrue, gentity_s::r, Rancor_CheckDropVictim(), Rancor_Combat(), Rancor_Crush(), Rancor_DropVictim(), Rancor_Idle(), Rancor_Patrol(), gentity_s::s, SCF_LOOK_FOR_ENEMIES, gNPC_t::scriptFlags, entityState_s::time, level_locals_t::time, TIMER_Done(), TIMER_Done2(), TIMER_Remove(), TIMER_Set(), va(), and ValidEnemy().

Referenced by NPC_BehaviorSet_Rancor().

00829 {
00830         AddSightEvent( NPC, NPC->r.currentOrigin, 1024, AEL_DANGER_GREAT, 50 );
00831 
00832         Rancor_Crush();
00833 
00834         NPC->client->ps.eFlags2 &= ~(EF2_USE_ALT_ANIM|EF2_GENERIC_NPC_FLAG);
00835         if ( NPC->count )
00836         {//holding someone
00837                 NPC->client->ps.eFlags2 |= EF2_USE_ALT_ANIM;
00838                 if ( NPC->count == 2 )
00839                 {//in my mouth
00840                         NPC->client->ps.eFlags2 |= EF2_GENERIC_NPC_FLAG;
00841                 }
00842         }
00843         else
00844         {
00845                 NPC->client->ps.eFlags2 &= ~(EF2_USE_ALT_ANIM|EF2_GENERIC_NPC_FLAG);
00846         }
00847 
00848         if ( TIMER_Done2( NPC, "clearGrabbed", qtrue ) )
00849         {
00850                 Rancor_DropVictim( NPC );
00851         }
00852         else if ( NPC->client->ps.legsAnim == BOTH_PAIN2 
00853                 && NPC->count == 1 
00854                 && NPC->activator )
00855         {
00856                 if ( !Q_irand( 0, 3 ) )
00857                 {
00858                         Rancor_CheckDropVictim();
00859                 }
00860         }
00861         if ( !TIMER_Done( NPC, "rageTime" ) )
00862         {//do nothing but roar first time we see an enemy
00863                 AddSoundEvent( NPC, NPC->r.currentOrigin, 1024, AEL_DANGER_GREAT, qfalse );//, qfalse );
00864                 NPC_FaceEnemy( qtrue );
00865                 return;
00866         }
00867         if ( NPC->enemy )
00868         {
00869                 /*
00870                 if ( NPC->enemy->client //enemy is a client
00871                         && (NPC->enemy->client->NPC_class == CLASS_UGNAUGHT || NPC->enemy->client->NPC_class == CLASS_JAWA )//enemy is a lowly jawa or ugnaught
00872                         && NPC->enemy->enemy != NPC//enemy's enemy is not me
00873                         && (!NPC->enemy->enemy || !NPC->enemy->enemy->client || NPC->enemy->enemy->client->NPC_class!=CLASS_RANCOR) )//enemy's enemy is not a client or is not a rancor (which is as scary as me anyway)
00874                 {//they should be scared of ME and no-one else
00875                         G_SetEnemy( NPC->enemy, NPC );
00876                 }
00877                 */
00878                 if ( TIMER_Done(NPC,"angrynoise") )
00879                 {
00880                         G_Sound( NPC, CHAN_AUTO, G_SoundIndex( va("sound/chars/rancor/misc/anger%d.wav", Q_irand(1, 3))) );
00881 
00882                         TIMER_Set( NPC, "angrynoise", Q_irand( 5000, 10000 ) );
00883                 }
00884                 else
00885                 {
00886                         AddSoundEvent( NPC, NPC->r.currentOrigin, 512, AEL_DANGER_GREAT, qfalse );//, qfalse );
00887                 }
00888                 if ( NPC->count == 2 && NPC->client->ps.legsAnim == BOTH_ATTACK3 )
00889                 {//we're still chewing our enemy up
00890                         NPC_UpdateAngles( qtrue, qtrue );
00891                         return;
00892                 }
00893                 //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
00894                 if( NPC->enemy->client && NPC->enemy->client->NPC_class == CLASS_RANCOR )
00895                 {//got mad at another Rancor, look for a valid enemy
00896                         if ( TIMER_Done( NPC, "rancorInfight" ) )
00897                         {
00898                                 NPC_CheckEnemyExt( qtrue );
00899                         }
00900                 }
00901                 else if ( !NPC->count )
00902                 {
00903                         if ( ValidEnemy( NPC->enemy ) == qfalse )
00904                         {
00905                                 TIMER_Remove( NPC, "lookForNewEnemy" );//make them look again right now
00906                                 if ( !NPC->enemy->inuse || level.time - NPC->enemy->s.time > Q_irand( 10000, 15000 ) )
00907                                 {//it's been a while since the enemy died, or enemy is completely gone, get bored with him
00908                                         NPC->enemy = NULL;
00909                                         Rancor_Patrol();
00910                                         NPC_UpdateAngles( qtrue, qtrue );
00911                                         return;
00912                                 }
00913                         }
00914                         if ( TIMER_Done( NPC, "lookForNewEnemy" ) )
00915                         {
00916                                 gentity_t *newEnemy, *sav_enemy = NPC->enemy;//FIXME: what about NPC->lastEnemy?
00917                                 NPC->enemy = NULL;
00918                                 newEnemy = NPC_CheckEnemy( NPCInfo->confusionTime < level.time, qfalse, qfalse );
00919                                 NPC->enemy = sav_enemy;
00920                                 if ( newEnemy && newEnemy != sav_enemy )
00921                                 {//picked up a new enemy!
00922                                         NPC->lastEnemy = NPC->enemy;
00923                                         G_SetEnemy( NPC, newEnemy );
00924                                         //hold this one for at least 5-15 seconds
00925                                         TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 5000, 15000 ) );
00926                                 }
00927                                 else
00928                                 {//look again in 2-5 secs
00929                                         TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 2000, 5000 ) );
00930                                 }
00931                         }
00932                 }
00933                 Rancor_Combat();
00934         }
00935         else 
00936         {
00937                 if ( TIMER_Done(NPC,"idlenoise") )
00938                 {
00939                         G_Sound( NPC, CHAN_AUTO, G_SoundIndex( va("sound/chars/rancor/snort_%d.wav", Q_irand(1, 2))) );
00940 
00941                         TIMER_Set( NPC, "idlenoise", Q_irand( 2000, 4000 ) );
00942                         AddSoundEvent( NPC, NPC->r.currentOrigin, 384, AEL_DANGER, qfalse );//, qfalse );
00943                 }
00944                 if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
00945                 {
00946                         Rancor_Patrol();
00947                 }
00948                 else
00949                 {
00950                         Rancor_Idle();
00951                 }
00952         }
00953 
00954         NPC_UpdateAngles( qtrue, qtrue );
00955 }

float NPC_EntRangeFromBolt gentity_t targEnt,
int  boltIndex
 

Definition at line 1742 of file NPC_utils.c.

References entityShared_t::currentOrigin, G_GetBoltPosition(), gentity_t, NPC, Q3_INFINITE, gentity_s::r, and vec3_t.

Referenced by NPC_EnemyRangeFromBolt().

01743 {
01744         vec3_t  org;
01745 
01746         if ( !targEnt )
01747         {
01748                 return Q3_INFINITE;
01749         }
01750 
01751         G_GetBoltPosition( NPC, boltIndex, org, 0 );
01752 
01753         return (Distance( targEnt->r.currentOrigin, org ));
01754 }

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

Definition at line 1761 of file NPC_utils.c.

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_Rancor_Pain gentity_t self,
gentity_t attacker,
int  damage
 

Definition at line 703 of file NPC_AI_Rancor.c.

References gentity_s::activator, entityState_s::angles, BOTH_ATTACK2, BOTH_MELEE1, BOTH_MELEE2, BOTH_PAIN1, BOTH_PAIN2, BOTH_STAND1TO2, CLASS_RANCOR, gentity_s::client, gNPC_t::consecutiveBlockedMoves, gentity_s::count, 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, Rancor_CheckRoar(), gentity_s::s, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, TIMER_Done(), TIMER_Remove(), TIMER_Set(), and VectorCopy.

Referenced by NPC_PainFunc(), and NPC_SetMiscDefaultData().

00704 {
00705         qboolean hitByRancor = qfalse;
00706         if ( attacker&&attacker->client&&attacker->client->NPC_class==CLASS_RANCOR )
00707         {
00708                 hitByRancor = qtrue;
00709         }
00710         if ( attacker 
00711                 && attacker->inuse 
00712                 && attacker != self->enemy
00713                 && !(attacker->flags&FL_NOTARGET) )
00714         {
00715                 if ( !self->count )
00716                 {
00717                         if ( (!attacker->s.number&&!Q_irand(0,3))
00718                                 || !self->enemy
00719                                 || self->enemy->health == 0
00720                                 || (self->enemy->client&&self->enemy->client->NPC_class == CLASS_RANCOR)
00721                                 || (self->NPC && self->NPC->consecutiveBlockedMoves>=10 && DistanceSquared( attacker->r.currentOrigin, self->r.currentOrigin ) < DistanceSquared( self->enemy->r.currentOrigin, self->r.currentOrigin )) ) 
00722                         {//if my enemy is dead (or attacked by player) and I'm not still holding/eating someone, turn on the attacker
00723                                 //FIXME: if can't nav to my enemy, take this guy if I can nav to him
00724                                 G_SetEnemy( self, attacker );
00725                                 TIMER_Set( self, "lookForNewEnemy", Q_irand( 5000, 15000 ) );
00726                                 if ( hitByRancor )
00727                                 {//stay mad at this Rancor for 2-5 secs before looking for attacker enemies
00728                                         TIMER_Set( self, "rancorInfight", Q_irand( 2000, 5000 ) );
00729                                 }
00730 
00731                         }
00732                 }
00733         }
00734         if ( (hitByRancor|| (self->count==1&&self->activator&&!Q_irand(0,4)) || Q_irand( 0, 200 ) < damage )//hit by rancor, hit while holding live victim, or took a lot of damage
00735                 && self->client->ps.legsAnim != BOTH_STAND1TO2
00736                 && TIMER_Done( self, "takingPain" ) )
00737         {
00738                 if ( !Rancor_CheckRoar( self ) )
00739                 {
00740                         if ( self->client->ps.legsAnim != BOTH_MELEE1
00741                                 && self->client->ps.legsAnim != BOTH_MELEE2
00742                                 && self->client->ps.legsAnim != BOTH_ATTACK2 )
00743                         {//cant interrupt one of the big attack anims
00744                                 /*
00745                                 if ( self->count != 1 
00746                                         || attacker == self->activator
00747                                         || (self->client->ps.legsAnim != BOTH_ATTACK1&&self->client->ps.legsAnim != BOTH_ATTACK3) )
00748                                 */
00749                                 {//if going to bite our victim, only victim can interrupt that anim
00750                                         if ( self->health > 100 || hitByRancor )
00751                                         {
00752                                                 TIMER_Remove( self, "attacking" );
00753 
00754                                                 VectorCopy( self->NPC->lastPathAngles, self->s.angles );
00755 
00756                                                 if ( self->count == 1 )
00757                                                 {
00758                                                         NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00759                                                 }
00760                                                 else
00761                                                 {
00762                                                         NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00763                                                 }
00764                                                 TIMER_Set( self, "takingPain", self->client->ps.legsTimer+Q_irand(0, 500) );
00765 
00766                                                 if ( self->NPC )
00767                                                 {
00768                                                         self->NPC->localState = LSTATE_WAITING;
00769                                                 }
00770                                         }
00771                                 }
00772                         }
00773                 }
00774                 //let go
00775                 /*
00776                 if ( !Q_irand( 0, 3 ) && self->count == 1 )
00777                 {
00778                         Rancor_DropVictim( self );
00779                 }
00780                 */
00781         }
00782 }

void NPC_Rancor_Precache void   ) 
 

Definition at line 36 of file NPC_AI_Rancor.c.

References G_SoundIndex(), and va().

00037 {
00038         int i;
00039         for ( i = 1; i < 3; i ++ )
00040         {
00041                 G_SoundIndex( va("sound/chars/rancor/snort_%d.wav", i) );
00042         }
00043         G_SoundIndex( "sound/chars/rancor/swipehit.wav" );
00044         G_SoundIndex( "sound/chars/rancor/chomp.wav" );
00045 }

void Rancor_Attack float  distance,
qboolean  doCharge
 

Definition at line 431 of file NPC_AI_Rancor.c.

References gentity_s::activator, AngleVectors(), BOTH_ATTACK1, BOTH_ATTACK2, BOTH_ATTACK3, BOTH_FALLDEATH1, BOTH_MELEE1, BOTH_MELEE2, BOTH_SWIM_IDLE1, CHAN_AUTO, gentity_s::client, gentity_s::count, entityShared_t::currentOrigin, DAMAGE_NO_ARMOR, DAMAGE_NO_HIT_LOC, DAMAGE_NO_KNOCKBACK, DAMAGE_NO_PROTECTION, EF_NODRAW, playerState_s::eFlags, gentity_s::enemy, ENTITYNUM_NONE, EV_DEATH1, EV_DEATH3, EV_JUMP, playerState_s::forceHandExtend, playerState_s::forceHandExtendTime, G2_MODELPART_HEAD, G2_MODELPART_WAIST, G_AddEvent(), G_Damage(), G_Dismember(), G_GetBoltPosition(), G_ScreenShake(), G_Sound(), G_SoundIndex(), playerState_s::groundEntityNum, HANDEXTEND_NONE, renderInfo_s::handLBolt, gentity_s::health, playerState_s::legsAnim, playerState_s::legsTimer, MOD_MELEE, gNPC_t::nextBStateThink, gentity_s::NPC, NPC, NPC_SetAnim(), NULL, gclient_s::ps, Q3_INFINITE, Q_irand(), qfalse, qtrue, gentity_s::r, Rancor_Bite(), Rancor_Smash(), Rancor_Swing(), random, gclient_s::renderInfo, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, SETANIM_TORSO, TIMER_Done2(), TIMER_Exists(), TIMER_Set(), playerState_s::torsoAnim, TossClientItems(), vec3_origin, vec3_t, VectorScale, VectorSet, playerState_s::velocity, playerState_s::viewangles, and YAW.

Referenced by Rancor_Combat().

00432 {
00433         if ( !TIMER_Exists( NPC, "attacking" ) )
00434         {
00435                 if ( NPC->count == 2 && NPC->activator )
00436                 {
00437                 }
00438                 else if ( NPC->count == 1 && NPC->activator )
00439                 {//holding enemy
00440                         if ( NPC->activator->health > 0 && Q_irand( 0, 1 ) )
00441                         {//quick bite
00442                                 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00443                                 TIMER_Set( NPC, "attack_dmg", 450 );
00444                         }
00445                         else
00446                         {//full eat
00447                                 NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK3, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00448                                 TIMER_Set( NPC, "attack_dmg", 900 );
00449                                 //Make victim scream in fright
00450                                 if ( NPC->activator->health > 0 && NPC->activator->client )
00451                                 {
00452                                         G_AddEvent( NPC->activator, Q_irand(EV_DEATH1, EV_DEATH3), 0 );
00453                                         NPC_SetAnim( NPC->activator, SETANIM_TORSO, BOTH_FALLDEATH1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00454                                         if ( NPC->activator->NPC )
00455                                         {//no more thinking for you
00456                                                 TossClientItems( NPC );
00457                                                 NPC->activator->NPC->nextBStateThink = Q3_INFINITE;
00458                                         }
00459                                 }
00460                         }
00461                 }
00462                 else if ( NPC->enemy->health > 0 && doCharge )
00463                 {//charge
00464                         vec3_t  fwd, yawAng;
00465                         VectorSet( yawAng, 0, NPC->client->ps.viewangles[YAW], 0 );
00466                         AngleVectors( yawAng, fwd, NULL, NULL );
00467                         VectorScale( fwd, distance*1.5f, NPC->client->ps.velocity );
00468                         NPC->client->ps.velocity[2] = 150;
00469                         NPC->client->ps.groundEntityNum = ENTITYNUM_NONE;
00470 
00471                         NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_MELEE2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00472                         TIMER_Set( NPC, "attack_dmg", 1250 );
00473                 }
00474                 else if ( !Q_irand(0, 1) )
00475                 {//smash
00476                         NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_MELEE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00477                         TIMER_Set( NPC, "attack_dmg", 1000 );
00478                 }
00479                 else
00480                 {//try to grab
00481                         NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00482                         TIMER_Set( NPC, "attack_dmg", 1000 );
00483                 }
00484 
00485                 TIMER_Set( NPC, "attacking", NPC->client->ps.legsTimer + random() * 200 );
00486         }
00487 
00488         // Need to do delayed damage since the attack animations encapsulate multiple mini-attacks
00489 
00490         if ( TIMER_Done2( NPC, "attack_dmg", qtrue ) )
00491         {
00492                 vec3_t shakePos;
00493                 switch ( NPC->client->ps.legsAnim )
00494                 {
00495                 case BOTH_MELEE1:
00496                         Rancor_Smash();
00497                         G_GetBoltPosition( NPC, NPC->client->renderInfo.handLBolt, shakePos, 0 );
00498                         G_ScreenShake( shakePos, NULL, 4.0f, 1000, qfalse );
00499                         //CGCam_Shake( 1.0f*playerDist/128.0f, 1000 );
00500                         break;
00501                 case BOTH_MELEE2:
00502                         Rancor_Bite();
00503                         TIMER_Set( NPC, "attack_dmg2", 450 );
00504                         break;
00505                 case BOTH_ATTACK1:
00506                         if ( NPC->count == 1 && NPC->activator )
00507                         {
00508                                 G_Damage( NPC->activator, NPC, NPC, vec3_origin, NPC->activator->r.currentOrigin, Q_irand( 25, 40 ), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_MELEE );
00509                                 if ( NPC->activator->health <= 0 )
00510                                 {//killed him
00511                                         //make it look like we bit his head off
00512                                         //NPC->activator->client->dismembered = qfalse;
00513                                         G_Dismember( NPC->activator, NPC, NPC->activator->r.currentOrigin, G2_MODELPART_HEAD, 90, 0, NPC->activator->client->ps.torsoAnim, qtrue);
00514                                         //G_DoDismemberment( NPC->activator, NPC->activator->r.currentOrigin, MOD_SABER, 1000, HL_HEAD, qtrue );
00515                                         NPC->activator->client->ps.forceHandExtend = HANDEXTEND_NONE;
00516                                         NPC->activator->client->ps.forceHandExtendTime = 0;
00517                                         NPC_SetAnim( NPC->activator, SETANIM_BOTH, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00518                                 }
00519                                 G_Sound( NPC->activator, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/chomp.wav" ) );
00520                         }
00521                         break;
00522                 case BOTH_ATTACK2:
00523                         //try to grab
00524                         Rancor_Swing( qtrue );
00525                         break;
00526                 case BOTH_ATTACK3:
00527                         if ( NPC->count == 1 && NPC->activator )
00528                         {
00529                                 //cut in half
00530                                 if ( NPC->activator->client )
00531                                 {
00532                                         //NPC->activator->client->dismembered = qfalse;
00533                                         G_Dismember( NPC->activator, NPC, NPC->activator->r.currentOrigin, G2_MODELPART_WAIST, 90, 0, NPC->activator->client->ps.torsoAnim, qtrue);
00534                                         //G_DoDismemberment( NPC->activator, NPC->enemy->r.currentOrigin, MOD_SABER, 1000, HL_WAIST, qtrue );
00535                                 }
00536                                 //KILL
00537                                 G_Damage( NPC->activator, NPC, NPC, vec3_origin, NPC->activator->r.currentOrigin, NPC->enemy->health+10, DAMAGE_NO_PROTECTION|DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, MOD_MELEE );//, HL_NONE );//
00538                                 if ( NPC->activator->client )
00539                                 {
00540                                         NPC->activator->client->ps.forceHandExtend = HANDEXTEND_NONE;
00541                                         NPC->activator->client->ps.forceHandExtendTime = 0;
00542                                         NPC_SetAnim( NPC->activator, SETANIM_BOTH, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00543                                 }
00544                                 TIMER_Set( NPC, "attack_dmg2", 1350 );
00545                                 G_Sound( NPC->activator, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/swipehit.wav" ) );
00546                                 G_AddEvent( NPC->activator, EV_JUMP, NPC->activator->health );
00547                         }
00548                         break;
00549                 }
00550         }
00551         else if ( TIMER_Done2( NPC, "attack_dmg2", qtrue ) )
00552         {
00553                 switch ( NPC->client->ps.legsAnim )
00554                 {
00555                 case BOTH_MELEE1:
00556                         break;
00557                 case BOTH_MELEE2:
00558                         Rancor_Bite();
00559                         break;
00560                 case BOTH_ATTACK1:
00561                         break;
00562                 case BOTH_ATTACK2:
00563                         break;
00564                 case BOTH_ATTACK3:
00565                         if ( NPC->count == 1 && NPC->activator )
00566                         {//swallow victim
00567                                 G_Sound( NPC->activator, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/chomp.wav" ) );
00568                                 //FIXME: sometimes end up with a live one in our mouths?
00569                                 //just make sure they're dead
00570                                 if ( NPC->activator->health > 0 )
00571                                 {
00572                                         //cut in half
00573                                         //NPC->activator->client->dismembered = qfalse;
00574                                         G_Dismember( NPC->activator, NPC, NPC->activator->r.currentOrigin, G2_MODELPART_WAIST, 90, 0, NPC->activator->client->ps.torsoAnim, qtrue);
00575                                         //G_DoDismemberment( NPC->activator, NPC->enemy->r.currentOrigin, MOD_SABER, 1000, HL_WAIST, qtrue );
00576                                         //KILL
00577                                         G_Damage( NPC->activator, NPC, NPC, vec3_origin, NPC->activator->r.currentOrigin, NPC->enemy->health+10, DAMAGE_NO_PROTECTION|DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, MOD_MELEE );//, HL_NONE );
00578                                         NPC->activator->client->ps.forceHandExtend = HANDEXTEND_NONE;
00579                                         NPC->activator->client->ps.forceHandExtendTime = 0;
00580                                         NPC_SetAnim( NPC->activator, SETANIM_BOTH, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00581                                         G_AddEvent( NPC->activator, EV_JUMP, NPC->activator->health );
00582                                 }
00583                                 if ( NPC->activator->client )
00584                                 {//*sigh*, can't get tags right, just remove them?
00585                                         NPC->activator->client->ps.eFlags |= EF_NODRAW;
00586                                 }
00587                                 NPC->count = 2;
00588                                 TIMER_Set( NPC, "clearGrabbed", 2600 );
00589                         }
00590                         break;
00591                 }
00592         }
00593         else if ( NPC->client->ps.legsAnim == BOTH_ATTACK2 )
00594         {
00595                 if ( NPC->client->ps.legsTimer >= 1200 && NPC->client->ps.legsTimer <= 1350 )
00596                 {
00597                         if ( Q_irand( 0, 2 ) )
00598                         {
00599                                 Rancor_Swing( qfalse );
00600                         }
00601                         else
00602                         {
00603                                 Rancor_Swing( qtrue );
00604                         }
00605                 }
00606                 else if ( NPC->client->ps.legsTimer >= 1100 && NPC->client->ps.legsTimer <= 1550 )
00607                 {
00608                         Rancor_Swing( qtrue );
00609                 }
00610         }
00611 
00612         // Just using this to remove the attacking flag at the right time
00613         TIMER_Done2( NPC, "attacking", qtrue );
00614 }

void Rancor_Bite void   ) 
 

Definition at line 369 of file NPC_AI_Rancor.c.

References BOTH_DEATH17, BOTH_DEATHBACKWARD2, CHAN_AUTO, gentity_s::client, renderInfo_s::crotchBolt, entityShared_t::currentOrigin, DAMAGE_NO_ARMOR, DAMAGE_NO_KNOCKBACK, EF2_HELD_BY_MONSTER, playerState_s::eFlags2, G2_MODELPART_HEAD, G2_MODELPART_RLEG, G2_MODELPART_WAIST, G_Damage(), G_Dismember(), g_entities, G_Sound(), G_SoundIndex(), gentity_t, gentity_s::health, gentity_s::inuse, MOD_MELEE, NPC, NPC_GetEntsNearBolt(), NPC_SetAnim(), NULL, gclient_s::ps, Q_irand(), qtrue, gentity_s::r, gclient_s::renderInfo, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, playerState_s::torsoAnim, vec3_origin, and vec3_t.

Referenced by Rancor_Attack().

00370 {
00371         int                     radiusEntNums[128];
00372         int                     numEnts;
00373         const float     radius = 100;
00374         const float     radiusSquared = (radius*radius);
00375         int                     i;
00376         vec3_t          boltOrg;
00377 
00378         numEnts = NPC_GetEntsNearBolt( radiusEntNums, radius, NPC->client->renderInfo.crotchBolt, boltOrg );//was gutBolt?
00379 
00380         for ( i = 0; i < numEnts; i++ )
00381         {
00382                 gentity_t *radiusEnt = &g_entities[radiusEntNums[i]];
00383                 if ( !radiusEnt->inuse )
00384                 {
00385                         continue;
00386                 }
00387                 
00388                 if ( radiusEnt == NPC )
00389                 {//Skip the rancor ent
00390                         continue;
00391                 }
00392                 
00393                 if ( radiusEnt->client == NULL )
00394                 {//must be a client
00395                         continue;
00396                 }
00397 
00398                 if ( (radiusEnt->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
00399                 {//can't be one already being held
00400                         continue;
00401                 }
00402                 
00403                 if ( DistanceSquared( radiusEnt->r.currentOrigin, boltOrg ) <= radiusSquared )
00404                 {
00405                         G_Damage( radiusEnt, NPC, NPC, vec3_origin, radiusEnt->r.currentOrigin, Q_irand( 15, 30 ), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_MELEE );
00406                         if ( radiusEnt->health <= 0 && radiusEnt->client )
00407                         {//killed them, chance of dismembering
00408                                 if ( !Q_irand( 0, 1 ) )
00409                                 {//bite something off
00410                                         int hitLoc = Q_irand( G2_MODELPART_HEAD, G2_MODELPART_RLEG );
00411                                         if ( hitLoc == G2_MODELPART_HEAD )
00412                                         {
00413                                                 NPC_SetAnim( radiusEnt, SETANIM_BOTH, BOTH_DEATH17, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00414                                         }
00415                                         else if ( hitLoc == G2_MODELPART_WAIST )
00416                                         {
00417                                                 NPC_SetAnim( radiusEnt, SETANIM_BOTH, BOTH_DEATHBACKWARD2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00418                                         }
00419                                         //radiusEnt->client->dismembered = qfalse;
00420                                         //FIXME: the limb should just disappear, cuz I ate it
00421                                         G_Dismember( radiusEnt, NPC, radiusEnt->r.currentOrigin, hitLoc, 90, 0, radiusEnt->client->ps.torsoAnim, qtrue);
00422                                         //G_DoDismemberment( radiusEnt, radiusEnt->r.currentOrigin, MOD_SABER, 1000, hitLoc, qtrue );
00423                                 }
00424                         }
00425                         G_Sound( radiusEnt, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/chomp.wav" ) );
00426                 }
00427         }
00428 }

void Rancor_CheckDropVictim void   ) 
 

Definition at line 784 of file NPC_AI_Rancor.c.

References entityShared_t::absmax, entityShared_t::absmin, gentity_s::activator, trace_t::allsolid, gentity_s::clipmask, entityShared_t::currentOrigin, trace_t::fraction, entityShared_t::maxs, entityShared_t::mins, NPC, entityState_s::number, gentity_s::r, Rancor_DropVictim(), gentity_s::s, trace_t::startsolid, trap_Trace(), vec3_t, and VectorSet.

Referenced by NPC_BSRancor_Default().

00785 {
00786         vec3_t mins;
00787         vec3_t maxs;
00788         vec3_t start; 
00789         vec3_t end; 
00790         trace_t trace;
00791 
00792         VectorSet( mins, NPC->activator->r.mins[0]-1, NPC->activator->r.mins[1]-1, 0 );
00793         VectorSet( maxs, NPC->activator->r.maxs[0]+1, NPC->activator->r.maxs[1]+1, 1 );
00794         VectorSet( start, NPC->activator->r.currentOrigin[0], NPC->activator->r.currentOrigin[1], NPC->activator->r.absmin[2] ); 
00795         VectorSet( end, NPC->activator->r.currentOrigin[0], NPC->activator->r.currentOrigin[1], NPC->activator->r.absmax[2]-1 ); 
00796 
00797         trap_Trace( &trace, start, mins, maxs, end, NPC->activator->s.number, NPC->activator->clipmask );
00798         if ( !trace.allsolid && !trace.startsolid && trace.fraction >= 1.0f )
00799         {
00800                 Rancor_DropVictim( NPC );
00801         }
00802 }

qboolean Rancor_CheckRoar gentity_t self  ) 
 

Definition at line 66 of file NPC_AI_Rancor.c.

References BOTH_STAND1TO2, gentity_s::client, EF2_ALERTED, playerState_s::eFlags2, gentity_t, playerState_s::legsTimer, NPC_SetAnim(), gclient_s::ps, qboolean, qfalse, qtrue, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, TIMER_Set(), and gentity_s::wait.

Referenced by NPC_Rancor_Pain(), and Rancor_Patrol().

00067 {
00068         if ( !self->wait )
00069         {//haven't ever gotten mad yet
00070                 self->wait = 1;//do this only once
00071                 self->client->ps.eFlags2 |= EF2_ALERTED;
00072                 NPC_SetAnim( self, SETANIM_BOTH, BOTH_STAND1TO2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00073                 TIMER_Set( self, "rageTime", self->client->ps.legsTimer );
00074                 return qtrue;
00075         }
00076         return qfalse;
00077 }

void Rancor_Combat void   ) 
 

Definition at line 617 of file NPC_AI_Rancor.c.

References gNPC_t::combatMove, gNPC_t::consecutiveBlockedMoves, gentity_s::count, entityShared_t::currentAngles, entityShared_t::currentOrigin, gentity_s::enemy, fabs(), gNPC_t::goalEntity, gNPC_t::goalRadius, gentity_s::health, InFOV3(), gNPC_t::localState, LSTATE_CLEAR, entityShared_t::maxs, MIN_DISTANCE, NPC, NPC_ClearLOS4(), NPC_FaceEnemy(), NPC_MoveToGoal(), NPC_UpdateAngles(), NPCInfo, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, Rancor_Attack(), Rancor_Move(), TIMER_Done(), TIMER_Done2(), TIMER_Set(), vec3_t, VectorSet, and YAW.

Referenced by NPC_BSRancor_Default().

00618 {
00619         if ( NPC->count )
00620         {//holding my enemy
00621                 if ( TIMER_Done2( NPC, "takingPain", qtrue ))
00622                 {
00623                         NPCInfo->localState = LSTATE_CLEAR;
00624                 }
00625                 else
00626                 {
00627                         Rancor_Attack( 0, qfalse );
00628                 }
00629                 NPC_UpdateAngles( qtrue, qtrue );
00630                 return;
00631         }
00632         // If we cannot see our target or we have somewhere to go, then do that
00633         if ( !NPC_ClearLOS4( NPC->enemy ) )//|| UpdateGoal( ))
00634         {
00635                 NPCInfo->combatMove = qtrue;
00636                 NPCInfo->goalEntity = NPC->enemy;
00637                 NPCInfo->goalRadius = MIN_DISTANCE;//MAX_DISTANCE;      // just get us within combat range
00638 
00639                 if ( !NPC_MoveToGoal( qtrue ) )
00640                 {//couldn't go after him?  Look for a new one
00641                         TIMER_Set( NPC, "lookForNewEnemy", 0 );
00642                         NPCInfo->consecutiveBlockedMoves++;
00643                 }
00644                 else 
00645                 {
00646                         NPCInfo->consecutiveBlockedMoves = 0;
00647                 }
00648                 return;
00649         }
00650 
00651         // Sometimes I have problems with facing the enemy I'm attacking, so force the issue so I don't look dumb
00652         NPC_FaceEnemy( qtrue );
00653 
00654         {
00655                 float   distance;
00656                 qboolean        advance;
00657                 qboolean        doCharge;
00658 
00659                 distance        = Distance( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin );        
00660                 advance = (qboolean)( distance > (NPC->r.maxs[0]+MIN_DISTANCE) ? qtrue : qfalse  );
00661                 doCharge = qfalse;
00662 
00663                 if ( advance )
00664                 {//have to get closer
00665                         vec3_t  yawOnlyAngles;
00666                         VectorSet( yawOnlyAngles, 0, NPC->r.currentAngles[YAW], 0 );
00667                         if ( NPC->enemy->health > 0
00668                                 && fabs(distance-250) <= 80 
00669                                 && InFOV3( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, yawOnlyAngles, 30, 30 ) )
00670                         {
00671                                 if ( !Q_irand( 0, 9 ) )
00672                                 {//go for the charge
00673                                         doCharge = qtrue;
00674                                         advance = qfalse;
00675                                 }
00676                         }
00677                 }
00678 
00679                 if (( advance /*|| NPCInfo->localState == LSTATE_WAITING*/ ) && TIMER_Done( NPC, "attacking" )) // waiting monsters can't attack
00680                 {
00681                         if ( TIMER_Done2( NPC, "takingPain", qtrue ))
00682                         {
00683                                 NPCInfo->localState = LSTATE_CLEAR;
00684                         }
00685                         else
00686                         {
00687                                 Rancor_Move( 1 );
00688                         }
00689                 }
00690                 else
00691                 {
00692                         Rancor_Attack( distance, doCharge );
00693                 }
00694         }
00695 }

void Rancor_Crush void   ) 
 

Definition at line 805 of file NPC_AI_Rancor.c.

References gentity_s::client, entityShared_t::currentOrigin, ENTITYNUM_WORLD, G_Damage(), g_entities, gentity_t, playerState_s::groundEntityNum, gentity_s::inuse, gentity_s::localAnimIndex, MOD_CRUSH, NPC, NULL, gclient_s::ps, and gentity_s::r.

Referenced by NPC_BSRancor_Default().

00806 {
00807         gentity_t *crush;
00808 
00809         if (!NPC ||
00810                 !NPC->client ||
00811                 NPC->client->ps.groundEntityNum >= ENTITYNUM_WORLD)
00812         { //nothing to crush
00813                 return;
00814         }
00815 
00816         crush = &g_entities[NPC->client->ps.groundEntityNum];
00817         if (crush->inuse && crush->client && !crush->localAnimIndex)
00818         { //a humanoid, smash them good.
00819                 G_Damage(crush, NPC, NPC, NULL, NPC->r.currentOrigin, 200, 0, MOD_CRUSH);
00820         }
00821 }

void Rancor_DropVictim gentity_t self  ) 
 

Definition at line 140 of file NPC_AI_Rancor.c.

References gentity_s::activator, gentity_s::client, gentity_s::count, entityShared_t::currentAngles, EF2_HELD_BY_MONSTER, EF_NODRAW, playerState_s::eFlags, playerState_s::eFlags2, gentity_s::enemy, ENTITYNUM_NONE, G_SetAngles(), gentity_t, playerState_s::hasLookTarget, gentity_s::health, playerState_s::legsTimer, level, playerState_s::lookTarget, gNPC_t::nextBStateThink, gentity_s::NPC, NULL, PITCH, gclient_s::ps, qfalse, gentity_s::r, ROLL, SetClientViewAngle(), level_locals_t::time, playerState_s::torsoTimer, and playerState_s::viewangles.

Referenced by NPC_BSRancor_Default(), player_die(), Rancor_CheckDropVictim(), and Rancor_Swing().

00141 {
00142         //FIXME: if Rancor dies, it should drop its victim.
00143         //FIXME: if Rancor is removed, it must remove its victim.
00144         if ( self->activator )
00145         {
00146                 if ( self->activator->client )
00147                 {
00148                         self->activator->client->ps.eFlags2 &= ~EF2_HELD_BY_MONSTER;
00149                         self->activator->client->ps.hasLookTarget = qfalse;
00150                         self->activator->client->ps.lookTarget = ENTITYNUM_NONE;
00151                         self->activator->client->ps.viewangles[ROLL] = 0;
00152                         SetClientViewAngle( self->activator, self->activator->client->ps.viewangles );
00153                         self->activator->r.currentAngles[PITCH] = self->activator->r.currentAngles[ROLL] = 0;
00154                         G_SetAngles( self->activator, self->activator->r.currentAngles );
00155                 }
00156                 if ( self->activator->health <= 0 )
00157                 {
00158                         //if ( self->activator->s.number )
00159                         {//never free player
00160                                 if ( self->count == 1 )
00161                                 {//in my hand, just drop them
00162                                         if ( self->activator->client )
00163                                         {
00164                                                 self->activator->client->ps.legsTimer = self->activator->client->ps.torsoTimer = 0;
00165                                                 //FIXME: ragdoll?
00166                                         }
00167                                 }
00168                                 else
00169                                 {
00170                                         if ( self->activator->client )
00171                                         {
00172                                                 self->activator->client->ps.eFlags |= EF_NODRAW;//so his corpse doesn't drop out of me...
00173                                         }
00174                                         //G_FreeEntity( self->activator );
00175                                 }
00176                         }
00177                 }
00178                 else
00179                 {
00180                         if ( self->activator->NPC )
00181                         {//start thinking again
00182                                 self->activator->NPC->nextBStateThink = level.time;
00183                         }
00184                         //clear their anim and let them fall
00185                         self->activator->client->ps.legsTimer = self->activator->client->ps.torsoTimer = 0;
00186                 }
00187                 if ( self->enemy == self->activator )
00188                 {
00189                         self->enemy = NULL;
00190                 }
00191                 self->activator = NULL;
00192         }
00193         self->count = 0;//drop him
00194 }

void Rancor_Idle void   ) 
 

Definition at line 53 of file NPC_AI_Rancor.c.

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

Referenced by NPC_BSRancor_Default(), and Rancor_Patrol().

00054 {
00055         NPCInfo->localState = LSTATE_CLEAR;
00056 
00057         //If we have somewhere to go, then do that
00058         if ( UpdateGoal() )
00059         {
00060                 ucmd.buttons &= ~BUTTON_WALKING;
00061                 NPC_MoveToGoal( qtrue );
00062         }
00063 }

void Rancor_Move qboolean  visible  ) 
 

Definition at line 115 of file NPC_AI_Rancor.c.

References gNPC_t::consecutiveBlockedMoves, gentity_s::enemy, gNPC_t::goalEntity, gNPC_t::goalRadius, gNPC_t::localState, LSTATE_WAITING, MAX_DISTANCE, NPC, NPC_MoveToGoal(), NPCInfo, and qtrue.

Referenced by Rancor_Combat().

00116 {
00117         if ( NPCInfo->localState != LSTATE_WAITING )
00118         {
00119                 NPCInfo->goalEntity = NPC->enemy;
00120                 if ( !NPC_MoveToGoal( qtrue ) )
00121                 {
00122                         NPCInfo->consecutiveBlockedMoves++;
00123                 }
00124                 else
00125                 {
00126                         NPCInfo->consecutiveBlockedMoves = 0;
00127                 }
00128                 NPCInfo->goalRadius = MAX_DISTANCE;     // just get us within combat range
00129         }
00130 }

void Rancor_Patrol void   ) 
 

Definition at line 83 of file NPC_AI_Rancor.c.

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

Referenced by NPC_BSRancor_Default().

00084 {
00085         NPCInfo->localState = LSTATE_CLEAR;
00086 
00087         //If we have somewhere to go, then do that
00088         if ( UpdateGoal() )
00089         {
00090                 ucmd.buttons &= ~BUTTON_WALKING;
00091                 NPC_MoveToGoal( qtrue );
00092         }
00093         else
00094         {
00095                 if ( TIMER_Done( NPC, "patrolTime" ))
00096                 {
00097                         TIMER_Set( NPC, "patrolTime", crandom() * 5000 + 5000 );
00098                 }
00099         }
00100 
00101         if ( NPC_CheckEnemyExt( qtrue ) == qfalse )
00102         {
00103                 Rancor_Idle();
00104                 return;
00105         }
00106         Rancor_CheckRoar( NPC );
00107         TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 5000, 15000 ) );
00108 }

void Rancor_SetBolts gentity_t self  ) 
 

Definition at line 19 of file NPC_AI_Rancor.c.

References gentity_s::client, 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().

00020 {
00021         if ( self && self->client )
00022         {
00023                 renderInfo_t *ri = &self->client->renderInfo;
00024                 ri->handRBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*r_hand" );
00025                 ri->handLBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*l_hand" );
00026                 ri->headBolt = trap_G2API_AddBolt( self->ghoul2, 0, "*head_eyes" );
00027                 ri->torsoBolt = trap_G2API_AddBolt( self->ghoul2, 0, "jaw_bone" );
00028         }
00029 }

void Rancor_Smash void   ) 
 

Definition at line 308 of file NPC_AI_Rancor.c.

References AddSoundEvent(), AEL_DANGER, CHAN_AUTO, CLASS_ATST, CLASS_RANCOR, gentity_s::client, entityShared_t::currentOrigin, DAMAGE_NO_ARMOR, DAMAGE_NO_KNOCKBACK, EF2_HELD_BY_MONSTER, playerState_s::eFlags2, ENTITYNUM_NONE, G_Damage(), g_entities, G_Knockdown(), G_Sound(), G_SoundIndex(), gentity_t, playerState_s::groundEntityNum, renderInfo_s::handLBolt, gentity_s::health, gentity_s::inuse, MOD_MELEE, NPC, gclient_s::NPC_class, NPC_GetEntsNearBolt(), NULL, gclient_s::ps, Q_irand(), qfalse, gentity_s::r, gclient_s::renderInfo, vec3_origin, and vec3_t.

Referenced by Rancor_Attack().

00309 {
00310         int                     radiusEntNums[128];
00311         int                     numEnts;
00312         const float     radius = 128;
00313         const float     halfRadSquared = ((radius/2)*(radius/2));
00314         const float     radiusSquared = (radius*radius);
00315         float           distSq;
00316         int                     i;
00317         vec3_t          boltOrg;
00318 
00319         AddSoundEvent( NPC, NPC->r.currentOrigin, 512, AEL_DANGER, qfalse );//, qtrue );
00320 
00321         numEnts = NPC_GetEntsNearBolt( radiusEntNums, radius, NPC->client->renderInfo.handLBolt, boltOrg );
00322 
00323         for ( i = 0; i < numEnts; i++ )
00324         {
00325                 gentity_t *radiusEnt = &g_entities[radiusEntNums[i]];
00326                 if ( !radiusEnt->inuse )
00327                 {
00328                         continue;
00329                 }
00330                 
00331                 if ( radiusEnt == NPC )
00332                 {//Skip the rancor ent
00333                         continue;
00334                 }
00335                 
00336                 if ( radiusEnt->client == NULL )
00337                 {//must be a client
00338                         continue;
00339                 }
00340 
00341                 if ( (radiusEnt->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
00342                 {//can't be one being held
00343                         continue;
00344                 }
00345                 
00346                 distSq = DistanceSquared( radiusEnt->r.currentOrigin, boltOrg );
00347                 if ( distSq <= radiusSquared )
00348                 {
00349                         G_Sound( radiusEnt, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/swipehit.wav" ) );
00350                         if ( distSq < halfRadSquared )
00351                         {//close enough to do damage, too
00352                                 G_Damage( radiusEnt, NPC, NPC, vec3_origin, radiusEnt->r.currentOrigin, Q_irand( 10, 25 ), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_MELEE );
00353                         }
00354                         if ( radiusEnt->health > 0 
00355                                 && radiusEnt->client
00356                                 && radiusEnt->client->NPC_class != CLASS_RANCOR
00357                                 && radiusEnt->client->NPC_class != CLASS_ATST )
00358                         {
00359                                 if ( distSq < halfRadSquared 
00360                                         || radiusEnt->client->ps.groundEntityNum != ENTITYNUM_NONE )
00361                                 {//within range of my fist or withing ground-shaking range and not in the air
00362                                         G_Knockdown( radiusEnt );//, NPC, vec3_origin, 100, qtrue );
00363                                 }
00364                         }
00365                 }
00366         }
00367 }

void Rancor_Swing qboolean  tryGrab  ) 
 

Definition at line 196 of file NPC_AI_Rancor.c.

References gentity_s::activator, AngleVectors(), BOTH_SWIM_IDLE1, CHAN_AUTO, CLASS_ATST, CLASS_GALAKMECH, CLASS_GONK, CLASS_INTERROGATOR, CLASS_MARK1, CLASS_MARK2, CLASS_MOUSE, CLASS_PROBE, CLASS_R2D2, CLASS_R5D2, CLASS_RANCOR, CLASS_REMOTE, CLASS_SEEKER, CLASS_SENTRY, CLASS_VEHICLE, gentity_s::client, gentity_s::count, entityShared_t::currentOrigin, DAMAGE_NO_ARMOR, DAMAGE_NO_KNOCKBACK, EF2_HELD_BY_MONSTER, playerState_s::eFlags2, gentity_s::enemy, flrand(), playerState_s::forceHandExtend, playerState_s::forceHandExtendTime, G_Damage(), g_entities, G_Knockdown(), G_Sound(), G_SoundIndex(), G_Throw(), gentity_t, HANDEXTEND_NONE, renderInfo_s::handRBolt, playerState_s::hasLookTarget, gentity_s::health, gentity_s::inuse, playerState_s::legsTimer, playerState_s::lookTarget, MOD_MELEE, NPC, gclient_s::NPC_class, NPC_GetEntsNearBolt(), NPC_SetAnim(), NULL, entityState_s::number, gentity_s::pain, PITCH, gclient_s::ps, Q_irand(), qtrue, gentity_s::r, Rancor_DropVictim(), gclient_s::renderInfo, gentity_s::s, SETANIM_BOTH, SETANIM_FLAG_HOLD, SETANIM_FLAG_OVERRIDE, TIMER_Remove(), TIMER_Set(), vec3_origin, vec3_t, VectorCopy, playerState_s::viewangles, and YAW.

Referenced by Rancor_Attack().

00197 {
00198         int                     radiusEntNums[128];
00199         int                     numEnts;
00200         const float     radius = 88;
00201         const float     radiusSquared = (radius*radius);
00202         int                     i;
00203         vec3_t          boltOrg;
00204 
00205         numEnts = NPC_GetEntsNearBolt( radiusEntNums, radius, NPC->client->renderInfo.handRBolt, boltOrg );
00206 
00207         for ( i = 0; i < numEnts; i++ )
00208         {
00209                 gentity_t *radiusEnt = &g_entities[radiusEntNums[i]];
00210                 if ( !radiusEnt->inuse )
00211                 {
00212                         continue;
00213                 }
00214                 
00215                 if ( radiusEnt == NPC )
00216                 {//Skip the rancor ent
00217                         continue;
00218                 }
00219                 
00220                 if ( radiusEnt->client == NULL )
00221                 {//must be a client
00222                         continue;
00223                 }
00224 
00225                 if ( (radiusEnt->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
00226                 {//can't be one already being held
00227                         continue;
00228                 }
00229                 
00230                 if ( DistanceSquared( radiusEnt->r.currentOrigin, boltOrg ) <= radiusSquared )
00231                 {
00232                         if ( tryGrab 
00233                                 && NPC->count != 1 //don't have one in hand or in mouth already - FIXME: allow one in hand and any number in mouth!
00234                                 && radiusEnt->client->NPC_class != CLASS_RANCOR
00235                                 && radiusEnt->client->NPC_class != CLASS_GALAKMECH
00236                                 && radiusEnt->client->NPC_class != CLASS_ATST
00237                                 && radiusEnt->client->NPC_class != CLASS_GONK
00238                                 && radiusEnt->client->NPC_class != CLASS_R2D2
00239                                 && radiusEnt->client->NPC_class != CLASS_R5D2
00240                                 && radiusEnt->client->NPC_class != CLASS_MARK1
00241                                 && radiusEnt->client->NPC_class != CLASS_MARK2
00242                                 && radiusEnt->client->NPC_class != CLASS_MOUSE
00243                                 && radiusEnt->client->NPC_class != CLASS_PROBE
00244                                 && radiusEnt->client->NPC_class != CLASS_SEEKER
00245                                 && radiusEnt->client->NPC_class != CLASS_REMOTE
00246                                 && radiusEnt->client->NPC_class != CLASS_SENTRY
00247                                 && radiusEnt->client->NPC_class != CLASS_INTERROGATOR
00248                                 && radiusEnt->client->NPC_class != CLASS_VEHICLE )
00249                         {//grab
00250                                 if ( NPC->count == 2 )
00251                                 {//have one in my mouth, remove him
00252                                         TIMER_Remove( NPC, "clearGrabbed" );
00253                                         Rancor_DropVictim( NPC );
00254                                 }
00255                                 NPC->enemy = radiusEnt;//make him my new best friend
00256                                 radiusEnt->client->ps.eFlags2 |= EF2_HELD_BY_MONSTER;
00257                                 //FIXME: this makes it so that the victim can't hit us with shots!  Just use activator or something
00258                                 radiusEnt->client->ps.hasLookTarget = qtrue;
00259                                 radiusEnt->client->ps.lookTarget = NPC->s.number;
00260                                 NPC->activator = radiusEnt;//remember him
00261                                 NPC->count = 1;//in my hand
00262                                 //wait to attack
00263                                 TIMER_Set( NPC, "attacking", NPC->client->ps.legsTimer + Q_irand(500, 2500) );
00264                                 if ( radiusEnt->health > 0 && radiusEnt->pain )
00265                                 {//do pain on enemy
00266                                         radiusEnt->pain( radiusEnt, NPC, 100 );
00267                                         //GEntity_PainFunc( radiusEnt, NPC, NPC, radiusEnt->r.currentOrigin, 0, MOD_CRUSH );
00268                                 }
00269                                 else if ( radiusEnt->client )
00270                                 {
00271                                         radiusEnt->client->ps.forceHandExtend = HANDEXTEND_NONE;
00272                                         radiusEnt->client->ps.forceHandExtendTime = 0;
00273                                         NPC_SetAnim( radiusEnt, SETANIM_BOTH, BOTH_SWIM_IDLE1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD );
00274                                 }
00275                         }
00276                         else
00277                         {//smack
00278                                 vec3_t pushDir;
00279                                 vec3_t angs;
00280 
00281                                 G_Sound( radiusEnt, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/swipehit.wav" ) );
00282                                 //actually push the enemy
00283                                 /*
00284                                 //VectorSubtract( radiusEnt->r.currentOrigin, boltOrg, pushDir );
00285                                 VectorSubtract( radiusEnt->r.currentOrigin, NPC->r.currentOrigin, pushDir );
00286                                 pushDir[2] = Q_flrand( 100, 200 );
00287                                 VectorNormalize( pushDir );
00288                                 */
00289                                 VectorCopy( NPC->client->ps.viewangles, angs );
00290                                 angs[YAW] += flrand( 25, 50 );
00291                                 angs[PITCH] = flrand( -25, -15 );
00292                                 AngleVectors( angs, pushDir, NULL, NULL );
00293                                 if ( radiusEnt->client->NPC_class != CLASS_RANCOR
00294                                         && radiusEnt->client->NPC_class != CLASS_ATST )
00295                                 {
00296                                         G_Damage( radiusEnt, NPC, NPC, vec3_origin, radiusEnt->r.currentOrigin, Q_irand( 25, 40 ), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_MELEE );
00297                                         G_Throw( radiusEnt, pushDir, 250 );
00298                                         if ( radiusEnt->health > 0 )
00299                                         {//do pain on enemy
00300                                                 G_Knockdown( radiusEnt );//, NPC, pushDir, 100, qtrue );
00301                                         }
00302                                 }
00303                         }
00304                 }
00305         }
00306 }

void TossClientItems gentity_t self  ) 
 

Definition at line 567 of file g_combat.c.

References playerState_s::ammo, weaponData_s::ammoIndex, BG_FindItemForPowerup(), BG_FindItemForWeapon(), entityState_s::bolt2, gentity_s::client, clientPersistant_t::cmd, gentity_s::count, Drop_Item(), EV_DESTROY_WEAPON_MODEL, entityState_s::eventParm, g_gametype, G_TempEntity(), gentity_t, gitem_t, GT_SIEGE, GT_TEAM, vmCvar_t::integer, level, entityState_s::number, gclient_s::pers, playerState_s::powerups, gclient_s::ps, PW_NUM_POWERUPS, gentity_s::r, gentity_s::s, STAT_WEAPONS, playerState_s::stats, SVF_BROADCAST, entityShared_t::svFlags, level_locals_t::time, vec3_origin, usercmd_s::weapon, entityState_s::weapon, WEAPON_DROPPING, weaponData, playerState_s::weaponstate, WP_BRYAR_PISTOL, WP_EMPLACED_GUN, WP_NONE, and WP_TURRET.

Referenced by ClientDisconnect(), player_die(), and Rancor_Attack().

00567                                         {
00568         gitem_t         *item;
00569         int                     weapon;
00570         float           angle;
00571         int                     i;
00572         gentity_t       *drop;
00573 
00574         if (g_gametype.integer == GT_SIEGE)
00575         { //just don't drop anything then
00576                 return;
00577         }
00578 
00579         // drop the weapon if not a gauntlet or machinegun
00580         weapon = self->s.weapon;
00581 
00582         // make a special check to see if they are changing to a new
00583         // weapon that isn't the mg or gauntlet.  Without this, a client
00584         // can pick up a weapon, be killed, and not drop the weapon because
00585         // their weapon change hasn't completed yet and they are still holding the MG.
00586         if ( weapon == WP_BRYAR_PISTOL) {
00587                 if ( self->client->ps.weaponstate == WEAPON_DROPPING ) {
00588                         weapon = self->client->pers.cmd.weapon;
00589                 }
00590                 if ( !( self->client->ps.stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
00591                         weapon = WP_NONE;
00592                 }
00593         }
00594 
00595         self->s.bolt2 = weapon;
00596 
00597         if ( weapon > WP_BRYAR_PISTOL && 
00598                 weapon != WP_EMPLACED_GUN &&
00599                 weapon != WP_TURRET &&
00600                 self->client->ps.ammo[ weaponData[weapon].ammoIndex ] ) {
00601                 gentity_t *te;
00602 
00603                 // find the item type for this weapon
00604                 item = BG_FindItemForWeapon( weapon );
00605 
00606                 // tell all clients to remove the weapon model on this guy until he respawns
00607                 te = G_TempEntity( vec3_origin, EV_DESTROY_WEAPON_MODEL );
00608                 te->r.svFlags |= SVF_BROADCAST;
00609                 te->s.eventParm = self->s.number;
00610 
00611                 // spawn the item
00612                 Drop_Item( self, item, 0 );
00613         }
00614 
00615         // drop all the powerups if not in teamplay
00616         if ( g_gametype.integer != GT_TEAM && g_gametype.integer != GT_SIEGE ) {
00617                 angle = 45;
00618                 for ( i = 1 ; i < PW_NUM_POWERUPS ; i++ ) {
00619                         if ( self->client->ps.powerups[ i ] > level.time ) {
00620                                 item = BG_FindItemForPowerup( i );
00621                                 if ( !item ) {
00622                                         continue;
00623                                 }
00624                                 drop = Drop_Item( self, item, angle );
00625                                 // decide how many seconds it has left
00626                                 drop->count = ( self->client->ps.powerups[ i ] - level.time ) / 1000;
00627                                 if ( drop->count < 1 ) {
00628                                         drop->count = 1;
00629                                 }
00630                                 angle += 45;
00631                         }
00632                 }
00633         }
00634 }