123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746 |
- // leave this line at the top of all AI_xxxx.cpp files for PCH reasons...
- #include "g_headers.h"
- #include "b_local.h"
- #include "g_nav.h"
- #define MIN_MELEE_RANGE 320
- #define MIN_MELEE_RANGE_SQR ( MIN_MELEE_RANGE * MIN_MELEE_RANGE )
- #define MIN_DISTANCE 128
- #define MIN_DISTANCE_SQR ( MIN_DISTANCE * MIN_DISTANCE )
- #define TURN_OFF 0x00000100
- #define LEFT_ARM_HEALTH 40
- #define RIGHT_ARM_HEALTH 40
- #define AMMO_POD_HEALTH 40
- #define BOWCASTER_VELOCITY 1300
- #define BOWCASTER_NPC_DAMAGE_EASY 12
- #define BOWCASTER_NPC_DAMAGE_NORMAL 24
- #define BOWCASTER_NPC_DAMAGE_HARD 36
- #define BOWCASTER_SIZE 2
- #define BOWCASTER_SPLASH_DAMAGE 0
- #define BOWCASTER_SPLASH_RADIUS 0
- //Local state enums
- enum
- {
- LSTATE_NONE = 0,
- LSTATE_ASLEEP,
- LSTATE_WAKEUP,
- LSTATE_FIRED0,
- LSTATE_FIRED1,
- LSTATE_FIRED2,
- LSTATE_FIRED3,
- LSTATE_FIRED4,
- };
- qboolean NPC_CheckPlayerTeamStealth( void );
- gentity_t *CreateMissile( vec3_t org, vec3_t dir, float vel, int life, gentity_t *owner, qboolean altFire = qfalse );
- void Mark1_BlasterAttack(qboolean advance);
- void DeathFX( gentity_t *ent );
- extern gitem_t *FindItemForAmmo( ammo_t ammo );
- /*
- -------------------------
- NPC_Mark1_Precache
- -------------------------
- */
- void NPC_Mark1_Precache(void)
- {
- G_SoundIndex( "sound/chars/mark1/misc/mark1_wakeup");
- G_SoundIndex( "sound/chars/mark1/misc/shutdown");
- G_SoundIndex( "sound/chars/mark1/misc/walk");
- G_SoundIndex( "sound/chars/mark1/misc/run");
- G_SoundIndex( "sound/chars/mark1/misc/death1");
- G_SoundIndex( "sound/chars/mark1/misc/death2");
- G_SoundIndex( "sound/chars/mark1/misc/anger");
- G_SoundIndex( "sound/chars/mark1/misc/mark1_fire");
- G_SoundIndex( "sound/chars/mark1/misc/mark1_pain");
- G_SoundIndex( "sound/chars/mark1/misc/mark1_explo");
- // G_EffectIndex( "small_chunks");
- G_EffectIndex( "env/med_explode2");
- G_EffectIndex( "explosions/probeexplosion1");
- G_EffectIndex( "blaster/smoke_bolton");
- G_EffectIndex( "bryar/muzzle_flash");
- G_EffectIndex( "explosions/droidexplosion1" );
- RegisterItem( FindItemForAmmo( AMMO_METAL_BOLTS));
- RegisterItem( FindItemForAmmo( AMMO_BLASTER ));
- RegisterItem( FindItemForWeapon( WP_BOWCASTER ));
- RegisterItem( FindItemForWeapon( WP_BRYAR_PISTOL ));
- }
- /*
- -------------------------
- NPC_Mark1_Part_Explode
- -------------------------
- */
- void NPC_Mark1_Part_Explode( gentity_t *self, int bolt )
- {
- if ( bolt >=0 )
- {
- mdxaBone_t boltMatrix;
- vec3_t org, dir;
- gi.G2API_GetBoltMatrix( self->ghoul2, self->playerModel,
- bolt,
- &boltMatrix, self->currentAngles, self->currentOrigin, (cg.time?cg.time:level.time),
- NULL, self->s.modelScale );
- gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, org );
- gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, dir );
- G_PlayEffect( "env/med_explode2", org, dir );
- G_PlayEffect( G_EffectIndex("blaster/smoke_bolton"), self->playerModel, bolt, self->s.number, org );
- }
- }
- /*
- -------------------------
- Mark1_Idle
- -------------------------
- */
- void Mark1_Idle( void )
- {
- NPC_BSIdle();
- NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_SLEEP1, SETANIM_FLAG_NORMAL );
- }
- /*
- -------------------------
- Mark1Dead_FireRocket
- - Shoot the left weapon, the multi-blaster
- -------------------------
- */
- void Mark1Dead_FireRocket (void)
- {
- mdxaBone_t boltMatrix;
- vec3_t muzzle1,muzzle_dir;
- int damage = 50;
- gi.G2API_GetBoltMatrix( NPC->ghoul2, NPC->playerModel,
- NPC->genericBolt5,
- &boltMatrix, NPC->currentAngles, NPC->currentOrigin, (cg.time?cg.time:level.time),
- NULL, NPC->s.modelScale );
- gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, muzzle1 );
- gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, muzzle_dir );
- G_PlayEffect( "bryar/muzzle_flash", muzzle1, muzzle_dir );
- G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/mark1_fire"));
- gentity_t *missile = CreateMissile( muzzle1, muzzle_dir, BOWCASTER_VELOCITY, 10000, NPC );
- missile->classname = "bowcaster_proj";
- missile->s.weapon = WP_BOWCASTER;
- VectorSet( missile->maxs, BOWCASTER_SIZE, BOWCASTER_SIZE, BOWCASTER_SIZE );
- VectorScale( missile->maxs, -1, missile->mins );
- missile->damage = damage;
- missile->dflags = DAMAGE_DEATH_KNOCKBACK;
- missile->methodOfDeath = MOD_ENERGY;
- missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
- missile->splashDamage = BOWCASTER_SPLASH_DAMAGE;
- missile->splashRadius = BOWCASTER_SPLASH_RADIUS;
- // we don't want it to bounce
- missile->bounceCount = 0;
- }
- /*
- -------------------------
- Mark1Dead_FireBlaster
- - Shoot the left weapon, the multi-blaster
- -------------------------
- */
- void Mark1Dead_FireBlaster (void)
- {
- vec3_t muzzle1,muzzle_dir;
- gentity_t *missile;
- mdxaBone_t boltMatrix;
- int bolt;
- bolt = NPC->genericBolt1;
- gi.G2API_GetBoltMatrix( NPC->ghoul2, NPC->playerModel,
- bolt,
- &boltMatrix, NPC->currentAngles, NPC->currentOrigin, (cg.time?cg.time:level.time),
- NULL, NPC->s.modelScale );
- gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, muzzle1 );
- gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, muzzle_dir );
- G_PlayEffect( "bryar/muzzle_flash", muzzle1, muzzle_dir );
- missile = CreateMissile( muzzle1, muzzle_dir, 1600, 10000, NPC );
- G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/mark1_fire"));
- missile->classname = "bryar_proj";
- missile->s.weapon = WP_BRYAR_PISTOL;
- missile->damage = 1;
- missile->dflags = DAMAGE_DEATH_KNOCKBACK;
- missile->methodOfDeath = MOD_ENERGY;
- missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
- }
- /*
- -------------------------
- Mark1_die
- -------------------------
- */
- void Mark1_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod,int dFlags,int hitLoc )
- {
- /*
- int anim;
- // Is he dead already?
- anim = self->client->ps.legsAnim;
- if (((anim==BOTH_DEATH1) || (anim==BOTH_DEATH2)) && (self->client->ps.torsoAnimTimer==0))
- { // This is because self->health keeps getting zeroed out. HL_NONE acts as health in this case.
- self->locationDamage[HL_NONE] += damage;
- if (self->locationDamage[HL_NONE] > 50)
- {
- DeathFX(self);
- self->client->ps.eFlags |= EF_NODRAW;
- self->contents = CONTENTS_CORPSE;
- // G_FreeEntity( self ); // Is this safe? I can't see why we'd mark it nodraw and then just leave it around??
- self->e_ThinkFunc = thinkF_G_FreeEntity;
- self->nextthink = level.time + FRAMETIME;
- }
- return;
- }
- */
- G_Sound( self, G_SoundIndex(va("sound/chars/mark1/misc/death%d.wav",Q_irand( 1, 2))));
- // Choose a death anim
- if (Q_irand( 1, 10) > 5)
- {
- NPC_SetAnim( self, SETANIM_BOTH, BOTH_DEATH2, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
- }
- else
- {
- NPC_SetAnim( self, SETANIM_BOTH, BOTH_DEATH1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
- }
- }
- /*
- -------------------------
- Mark1_dying
- -------------------------
- */
- void Mark1_dying( gentity_t *self )
- {
- int num,newBolt;
- if (self->client->ps.torsoAnimTimer>0)
- {
- if (TIMER_Done(self,"dyingExplosion"))
- {
- num = Q_irand( 1, 3);
- // Find place to generate explosion
- if (num == 1)
- {
- num = Q_irand( 8, 10);
- newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], va("*flash%d",num) );
- NPC_Mark1_Part_Explode(self,newBolt);
- }
- else
- {
- num = Q_irand( 1, 6);
- newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], va("*torso_tube%d",num) );
- NPC_Mark1_Part_Explode(self,newBolt);
- gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], va("torso_tube%d",num), TURN_OFF );
- }
- TIMER_Set( self, "dyingExplosion", Q_irand( 300, 1000 ) );
- }
- // int dir;
- // vec3_t right;
- // Shove to the side
- // AngleVectors( self->client->renderInfo.eyeAngles, NULL, right, NULL );
- // VectorMA( self->client->ps.velocity, -80, right, self->client->ps.velocity );
- // See which weapons are there
- // Randomly fire blaster
- if (!gi.G2API_GetSurfaceRenderStatus( &self->ghoul2[self->playerModel], "l_arm" )) // Is the blaster still on the model?
- {
- if (Q_irand( 1, 5) == 1)
- {
- SaveNPCGlobals();
- SetNPCGlobals( self );
- Mark1Dead_FireBlaster();
- RestoreNPCGlobals();
- }
- }
- // Randomly fire rocket
- if (!gi.G2API_GetSurfaceRenderStatus( &self->ghoul2[self->playerModel], "r_arm" )) // Is the rocket still on the model?
- {
- if (Q_irand( 1, 10) == 1)
- {
- SaveNPCGlobals();
- SetNPCGlobals( self );
- Mark1Dead_FireRocket();
- RestoreNPCGlobals();
- }
- }
- }
- }
- /*
- -------------------------
- NPC_Mark1_Pain
- - look at what was hit and see if it should be removed from the model.
- -------------------------
- */
- void NPC_Mark1_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, const vec3_t point, int damage, int mod,int hitLoc )
- {
- int newBolt,i,chance;
-
- NPC_Pain( self, inflictor, other, point, damage, mod );
- G_Sound( self, G_SoundIndex("sound/chars/mark1/misc/mark1_pain"));
- // Hit in the CHEST???
- if (hitLoc==HL_CHEST)
- {
- chance = Q_irand( 1, 4);
-
- if ((chance == 1) && (damage > 5))
- {
- NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
- }
- }
- // Hit in the left arm?
- else if ((hitLoc==HL_ARM_LT) && (self->locationDamage[HL_ARM_LT] > LEFT_ARM_HEALTH))
- {
- if (self->locationDamage[hitLoc] >= LEFT_ARM_HEALTH) // Blow it up?
- {
- newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*flash3" );
- if ( newBolt != -1 )
- {
- NPC_Mark1_Part_Explode(self,newBolt);
- }
- gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "l_arm", TURN_OFF );
- }
- }
- // Hit in the right arm?
- else if ((hitLoc==HL_ARM_RT) && (self->locationDamage[HL_ARM_RT] > RIGHT_ARM_HEALTH)) // Blow it up?
- {
- if (self->locationDamage[hitLoc] >= RIGHT_ARM_HEALTH)
- {
- newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*flash4" );
- if ( newBolt != -1 )
- {
- // G_PlayEffect( "small_chunks", self->playerModel, self->genericBolt2, self->s.number);
- NPC_Mark1_Part_Explode( self, newBolt );
- }
- gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "r_arm", TURN_OFF );
- }
- }
- // Check ammo pods
- else
- {
- for (i=0;i<6;i++)
- {
- if ((hitLoc==HL_GENERIC1+i) && (self->locationDamage[HL_GENERIC1+i] > AMMO_POD_HEALTH)) // Blow it up?
- {
- if (self->locationDamage[hitLoc] >= AMMO_POD_HEALTH)
- {
- newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], va("*torso_tube%d",(i+1)) );
- if ( newBolt != -1 )
- {
- NPC_Mark1_Part_Explode(self,newBolt);
- }
- gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], va("torso_tube%d",(i+1)), TURN_OFF );
- NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
- break;
- }
- }
- }
- }
- // Are both guns shot off?
- if ((gi.G2API_GetSurfaceRenderStatus( &self->ghoul2[self->playerModel], "l_arm" )) &&
- (gi.G2API_GetSurfaceRenderStatus( &self->ghoul2[self->playerModel], "r_arm" )))
- {
- G_Damage(self,NULL,NULL,NULL,NULL,self->health,0,MOD_UNKNOWN);
- }
- }
- /*
- -------------------------
- Mark1_Hunt
- - look for enemy.
- -------------------------`
- */
- void Mark1_Hunt(void)
- {
- if ( NPCInfo->goalEntity == NULL )
- {
- NPCInfo->goalEntity = NPC->enemy;
- }
- NPC_FaceEnemy( qtrue );
- NPCInfo->combatMove = qtrue;
- NPC_MoveToGoal( qtrue );
- }
- /*
- -------------------------
- Mark1_FireBlaster
- - Shoot the left weapon, the multi-blaster
- -------------------------
- */
- void Mark1_FireBlaster(void)
- {
- vec3_t muzzle1,enemy_org1,delta1,angleToEnemy1;
- static vec3_t forward, vright, up;
- static vec3_t muzzle;
- gentity_t *missile;
- mdxaBone_t boltMatrix;
- int bolt;
- // Which muzzle to fire from?
- if ((NPCInfo->localState <= LSTATE_FIRED0) || (NPCInfo->localState == LSTATE_FIRED4))
- {
- NPCInfo->localState = LSTATE_FIRED1;
- bolt = NPC->genericBolt1;
- }
- else if (NPCInfo->localState == LSTATE_FIRED1)
- {
- NPCInfo->localState = LSTATE_FIRED2;
- bolt = NPC->genericBolt2;
- }
- else if (NPCInfo->localState == LSTATE_FIRED2)
- {
- NPCInfo->localState = LSTATE_FIRED3;
- bolt = NPC->genericBolt3;
- }
- else
- {
- NPCInfo->localState = LSTATE_FIRED4;
- bolt = NPC->genericBolt4;
- }
- gi.G2API_GetBoltMatrix( NPC->ghoul2, NPC->playerModel,
- bolt,
- &boltMatrix, NPC->currentAngles, NPC->currentOrigin, (cg.time?cg.time:level.time),
- NULL, NPC->s.modelScale );
- gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, muzzle1 );
- if (NPC->health)
- {
- CalcEntitySpot( NPC->enemy, SPOT_HEAD, enemy_org1 );
- VectorSubtract (enemy_org1, muzzle1, delta1);
- vectoangles ( delta1, angleToEnemy1 );
- AngleVectors (angleToEnemy1, forward, vright, up);
- }
- else
- {
- AngleVectors (NPC->currentAngles, forward, vright, up);
- }
- G_PlayEffect( "bryar/muzzle_flash", muzzle1, forward );
- G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/mark1_fire"));
- missile = CreateMissile( muzzle1, forward, 1600, 10000, NPC );
- missile->classname = "bryar_proj";
- missile->s.weapon = WP_BRYAR_PISTOL;
- missile->damage = 1;
- missile->dflags = DAMAGE_DEATH_KNOCKBACK;
- missile->methodOfDeath = MOD_ENERGY;
- missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
- }
- /*
- -------------------------
- Mark1_BlasterAttack
- -------------------------
- */
- void Mark1_BlasterAttack(qboolean advance )
- {
- int chance;
- if ( TIMER_Done( NPC, "attackDelay" ) ) // Attack?
- {
- chance = Q_irand( 1, 5);
-
- NPCInfo->burstCount++;
- if (NPCInfo->burstCount<3) // Too few shots this burst?
- {
- chance = 2; // Force it to keep firing.
- }
- else if (NPCInfo->burstCount>12) // Too many shots fired this burst?
- {
- NPCInfo->burstCount = 0;
- chance = 1; // Force it to stop firing.
- }
- // Stop firing.
- if (chance == 1)
- {
- NPCInfo->burstCount = 0;
- TIMER_Set( NPC, "attackDelay", Q_irand( 1000, 3000) );
- NPC->client->ps.torsoAnimTimer=0; // Just in case the firing anim is running.
- }
- else
- {
- if (TIMER_Done( NPC, "attackDelay2" )) // Can't be shooting every frame.
- {
- TIMER_Set( NPC, "attackDelay2", Q_irand( 50, 50) );
- Mark1_FireBlaster();
- NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
- }
- return;
- }
- }
- else if (advance)
- {
- if ( NPC->client->ps.torsoAnim == BOTH_ATTACK1 )
- {
- NPC->client->ps.torsoAnimTimer=0; // Just in case the firing anim is running.
- }
- Mark1_Hunt();
- }
- else // Make sure he's not firing.
- {
- if ( NPC->client->ps.torsoAnim == BOTH_ATTACK1 )
- {
- NPC->client->ps.torsoAnimTimer=0; // Just in case the firing anim is running.
- }
- }
- }
- /*
- -------------------------
- Mark1_FireRocket
- -------------------------
- */
- void Mark1_FireRocket(void)
- {
- mdxaBone_t boltMatrix;
- vec3_t muzzle1,enemy_org1,delta1,angleToEnemy1;
- static vec3_t forward, vright, up;
- int damage = 50;
- gi.G2API_GetBoltMatrix( NPC->ghoul2, NPC->playerModel,
- NPC->genericBolt5,
- &boltMatrix, NPC->currentAngles, NPC->currentOrigin, (cg.time?cg.time:level.time),
- NULL, NPC->s.modelScale );
- gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, muzzle1 );
- // G_PlayEffect( "blaster/muzzle_flash", muzzle1 );
- CalcEntitySpot( NPC->enemy, SPOT_HEAD, enemy_org1 );
- VectorSubtract (enemy_org1, muzzle1, delta1);
- vectoangles ( delta1, angleToEnemy1 );
- AngleVectors (angleToEnemy1, forward, vright, up);
- G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/mark1_fire" ));
- gentity_t *missile = CreateMissile( muzzle1, forward, BOWCASTER_VELOCITY, 10000, NPC );
- missile->classname = "bowcaster_proj";
- missile->s.weapon = WP_BOWCASTER;
- VectorSet( missile->maxs, BOWCASTER_SIZE, BOWCASTER_SIZE, BOWCASTER_SIZE );
- VectorScale( missile->maxs, -1, missile->mins );
- missile->damage = damage;
- missile->dflags = DAMAGE_DEATH_KNOCKBACK;
- missile->methodOfDeath = MOD_ENERGY;
- missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
- missile->splashDamage = BOWCASTER_SPLASH_DAMAGE;
- missile->splashRadius = BOWCASTER_SPLASH_RADIUS;
- // we don't want it to bounce
- missile->bounceCount = 0;
- }
- /*
- -------------------------
- Mark1_RocketAttack
- -------------------------
- */
- void Mark1_RocketAttack( qboolean advance )
- {
- if ( TIMER_Done( NPC, "attackDelay" ) ) // Attack?
- {
- TIMER_Set( NPC, "attackDelay", Q_irand( 1000, 3000) );
- NPC_SetAnim( NPC, SETANIM_TORSO, BOTH_ATTACK2, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
- Mark1_FireRocket();
- }
- else if (advance)
- {
- Mark1_Hunt();
- }
- }
- /*
- -------------------------
- Mark1_AttackDecision
- -------------------------
- */
- void Mark1_AttackDecision( void )
- {
- int blasterTest,rocketTest;
- //randomly talk
- if ( TIMER_Done(NPC,"patrolNoise") )
- {
- if (TIMER_Done(NPC,"angerNoise"))
- {
- // G_Sound( NPC, G_SoundIndex(va("sound/chars/mark1/misc/talk%d.wav", Q_irand(1, 4))));
- TIMER_Set( NPC, "patrolNoise", Q_irand( 4000, 10000 ) );
- }
- }
- // Enemy is dead or he has no enemy.
- if ((NPC->enemy->health<1) || ( NPC_CheckEnemyExt() == qfalse ))
- {
- NPC->enemy = NULL;
- return;
- }
- // Rate our distance to the target and visibility
- float distance = (int) DistanceHorizontalSquared( NPC->currentOrigin, NPC->enemy->currentOrigin );
- distance_e distRate = ( distance > MIN_MELEE_RANGE_SQR ) ? DIST_LONG : DIST_MELEE;
- qboolean visible = NPC_ClearLOS( NPC->enemy );
- qboolean advance = (qboolean)(distance > MIN_DISTANCE_SQR);
- // If we cannot see our target, move to see it
- if ((!visible) || (!NPC_FaceEnemy(qtrue)))
- {
- Mark1_Hunt();
- return;
- }
- // See if the side weapons are there
- blasterTest = gi.G2API_GetSurfaceRenderStatus( &NPC->ghoul2[NPC->playerModel], "l_arm" );
- rocketTest = gi.G2API_GetSurfaceRenderStatus( &NPC->ghoul2[NPC->playerModel], "r_arm" );
- // It has both side weapons
- if (!blasterTest && !rocketTest)
- {
- ; // So do nothing.
- }
- else if (blasterTest)
- {
- distRate = DIST_LONG;
- }
- else if (rocketTest)
- {
- distRate = DIST_MELEE;
- }
- else // It should never get here, but just in case
- {
- NPC->health = 0;
- NPC->client->ps.stats[STAT_HEALTH] = 0;
- GEntity_DieFunc(NPC, NPC, NPC, 100, MOD_UNKNOWN);
- }
- // We can see enemy so shoot him if timers let you.
- NPC_FaceEnemy( qtrue );
- if (distRate == DIST_MELEE)
- {
- Mark1_BlasterAttack(advance);
- }
- else if (distRate == DIST_LONG)
- {
- Mark1_RocketAttack(advance);
- }
- }
- /*
- -------------------------
- Mark1_Patrol
- -------------------------
- */
- void Mark1_Patrol( void )
- {
- if ( NPC_CheckPlayerTeamStealth() )
- {
- G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/mark1_wakeup"));
- NPC_UpdateAngles( qtrue, qtrue );
- return;
- }
- //If we have somewhere to go, then do that
- if (!NPC->enemy)
- {
- if ( UpdateGoal() )
- {
- ucmd.buttons |= BUTTON_WALKING;
- NPC_MoveToGoal( qtrue );
- NPC_UpdateAngles( qtrue, qtrue );
- }
- //randomly talk
- // if (TIMER_Done(NPC,"patrolNoise"))
- // {
- // G_Sound( NPC, G_SoundIndex(va("sound/chars/mark1/misc/talk%d.wav", Q_irand(1, 4))));
- //
- // TIMER_Set( NPC, "patrolNoise", Q_irand( 2000, 4000 ) );
- // }
- }
- }
- /*
- -------------------------
- NPC_BSMark1_Default
- -------------------------
- */
- void NPC_BSMark1_Default( void )
- {
- //NPC->e_DieFunc = dieF_Mark1_die;
- if ( NPC->enemy )
- {
- NPCInfo->goalEntity = NPC->enemy;
- Mark1_AttackDecision();
- }
- else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
- {
- Mark1_Patrol();
- }
- else
- {
- Mark1_Idle();
- }
- }
|