123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456 |
- // 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"
- void Interrogator_Idle( void );
- void DeathFX( gentity_t *ent );
- enum
- {
- LSTATE_BLADESTOP=0,
- LSTATE_BLADEUP,
- LSTATE_BLADEDOWN,
- };
- /*
- -------------------------
- NPC_Interrogator_Precache
- -------------------------
- */
- void NPC_Interrogator_Precache(gentity_t *self)
- {
- G_SoundIndex( "sound/chars/interrogator/misc/torture_droid_lp" );
- G_SoundIndex("sound/chars/mark1/misc/anger.wav");
- G_SoundIndex( "sound/chars/probe/misc/talk");
- G_SoundIndex( "sound/chars/interrogator/misc/torture_droid_inject" );
- G_SoundIndex( "sound/chars/interrogator/misc/int_droid_explo" );
- G_EffectIndex( "explosions/droidexplosion1" );
- }
- /*
- -------------------------
- Interrogator_die
- -------------------------
- */
- void Interrogator_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod,int dFlags,int hitLoc )
- {
- self->client->ps.velocity[2] = -100;
- /*
- self->locationDamage[HL_NONE] += damage;
- if (self->locationDamage[HL_NONE] > 40)
- {
- DeathFX(self);
- self->client->ps.eFlags |= EF_NODRAW;
- self->contents = CONTENTS_CORPSE;
- }
- else
- */
- {
- self->client->moveType = MT_WALK;
- self->client->ps.velocity[0] = Q_irand( -10, -20 );
- self->client->ps.velocity[1] = Q_irand( -10, -20 );
- self->client->ps.velocity[2] = -100;
- }
- //self->takedamage = qfalse;
- //self->client->ps.eFlags |= EF_NODRAW;
- //self->contents = 0;
- return;
- }
- /*
- -------------------------
- Interrogator_PartsMove
- -------------------------
- */
- void Interrogator_PartsMove(void)
- {
- // Syringe
- if ( TIMER_Done(NPC,"syringeDelay") )
- {
- NPC->pos1[1] = AngleNormalize360( NPC->pos1[1]);
- if ((NPC->pos1[1] < 60) || (NPC->pos1[1] > 300))
- {
- NPC->pos1[1]+=Q_irand( -20, 20 ); // Pitch
- }
- else if (NPC->pos1[1] > 180)
- {
- NPC->pos1[1]=Q_irand( 300, 360 ); // Pitch
- }
- else
- {
- NPC->pos1[1]=Q_irand( 0, 60 ); // Pitch
- }
- gi.G2API_SetBoneAnglesIndex( &NPC->ghoul2[NPC->playerModel], NPC->genericBone1, NPC->pos1, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL );
- TIMER_Set( NPC, "syringeDelay", Q_irand( 100, 1000 ) );
- }
- // Scalpel
- if ( TIMER_Done(NPC,"scalpelDelay") )
- {
- // Change pitch
- if ( NPCInfo->localState == LSTATE_BLADEDOWN ) // Blade is moving down
- {
- NPC->pos2[0]-= 30;
- if (NPC->pos2[0] < 180)
- {
- NPC->pos2[0] = 180;
- NPCInfo->localState = LSTATE_BLADEUP; // Make it move up
- }
- }
- else // Blade is coming back up
- {
- NPC->pos2[0]+= 30;
- if (NPC->pos2[0] >= 360)
- {
- NPC->pos2[0] = 360;
- NPCInfo->localState = LSTATE_BLADEDOWN; // Make it move down
- TIMER_Set( NPC, "scalpelDelay", Q_irand( 100, 1000 ) );
- }
- }
- NPC->pos2[0] = AngleNormalize360( NPC->pos2[0]);
- gi.G2API_SetBoneAnglesIndex( &NPC->ghoul2[NPC->playerModel], NPC->genericBone2, NPC->pos2, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL );
- }
- // Claw
- NPC->pos3[1] += Q_irand( 10, 30 );
- NPC->pos3[1] = AngleNormalize360( NPC->pos3[1]);
- gi.G2API_SetBoneAnglesIndex( &NPC->ghoul2[NPC->playerModel], NPC->genericBone3, NPC->pos3, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL );
- }
- #define VELOCITY_DECAY 0.85f
- #define HUNTER_UPWARD_PUSH 2
- /*
- -------------------------
- Interrogator_MaintainHeight
- -------------------------
- */
- void Interrogator_MaintainHeight( void )
- {
- float dif;
- // vec3_t endPos;
- // trace_t trace;
- NPC->s.loopSound = G_SoundIndex( "sound/chars/interrogator/misc/torture_droid_lp" );
- // Update our angles regardless
- NPC_UpdateAngles( qtrue, qtrue );
- // If we have an enemy, we should try to hover at about enemy eye level
- if ( NPC->enemy )
- {
- // Find the height difference
- dif = (NPC->enemy->currentOrigin[2] + NPC->enemy->maxs[2]) - NPC->currentOrigin[2];
- // cap to prevent dramatic height shifts
- if ( fabs( dif ) > 2 )
- {
- if ( fabs( dif ) > 16 )
- {
- dif = ( dif < 0 ? -16 : 16 );
- }
- NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2;
- }
- }
- else
- {
- gentity_t *goal = NULL;
- if ( NPCInfo->goalEntity ) // Is there a goal?
- {
- goal = NPCInfo->goalEntity;
- }
- else
- {
- goal = NPCInfo->lastGoalEntity;
- }
- if ( goal )
- {
- dif = goal->currentOrigin[2] - NPC->currentOrigin[2];
- if ( fabs( dif ) > 24 )
- {
- ucmd.upmove = ( ucmd.upmove < 0 ? -4 : 4 );
- }
- else
- {
- if ( NPC->client->ps.velocity[2] )
- {
- NPC->client->ps.velocity[2] *= VELOCITY_DECAY;
- if ( fabs( NPC->client->ps.velocity[2] ) < 2 )
- {
- NPC->client->ps.velocity[2] = 0;
- }
- }
- }
- }
- // Apply friction
- else if ( NPC->client->ps.velocity[2] )
- {
- NPC->client->ps.velocity[2] *= VELOCITY_DECAY;
- if ( fabs( NPC->client->ps.velocity[2] ) < 1 )
- {
- NPC->client->ps.velocity[2] = 0;
- }
- }
- }
- // Apply friction
- if ( NPC->client->ps.velocity[0] )
- {
- NPC->client->ps.velocity[0] *= VELOCITY_DECAY;
- if ( fabs( NPC->client->ps.velocity[0] ) < 1 )
- {
- NPC->client->ps.velocity[0] = 0;
- }
- }
- if ( NPC->client->ps.velocity[1] )
- {
- NPC->client->ps.velocity[1] *= VELOCITY_DECAY;
- if ( fabs( NPC->client->ps.velocity[1] ) < 1 )
- {
- NPC->client->ps.velocity[1] = 0;
- }
- }
- }
- #define HUNTER_STRAFE_VEL 32
- #define HUNTER_STRAFE_DIS 200
- /*
- -------------------------
- Interrogator_Strafe
- -------------------------
- */
- void Interrogator_Strafe( void )
- {
- int dir;
- vec3_t end, right;
- trace_t tr;
- float dif;
- AngleVectors( NPC->client->renderInfo.eyeAngles, NULL, right, NULL );
- // Pick a random strafe direction, then check to see if doing a strafe would be
- // reasonable valid
- dir = ( rand() & 1 ) ? -1 : 1;
- VectorMA( NPC->currentOrigin, HUNTER_STRAFE_DIS * dir, right, end );
- gi.trace( &tr, NPC->currentOrigin, NULL, NULL, end, NPC->s.number, MASK_SOLID );
- // Close enough
- if ( tr.fraction > 0.9f )
- {
- VectorMA( NPC->client->ps.velocity, HUNTER_STRAFE_VEL * dir, right, NPC->client->ps.velocity );
- // Add a slight upward push
- if ( NPC->enemy )
- {
- // Find the height difference
- dif = (NPC->enemy->currentOrigin[2] + 32) - NPC->currentOrigin[2];
- // cap to prevent dramatic height shifts
- if ( fabs( dif ) > 8 )
- {
- dif = ( dif < 0 ? -HUNTER_UPWARD_PUSH : HUNTER_UPWARD_PUSH );
- }
- NPC->client->ps.velocity[2] += dif;
- }
- // Set the strafe start time
- NPC->fx_time = level.time;
- NPCInfo->standTime = level.time + 3000 + random() * 500;
- }
- }
- /*
- -------------------------
- Interrogator_Hunt
- -------------------------`
- */
- #define HUNTER_FORWARD_BASE_SPEED 10
- #define HUNTER_FORWARD_MULTIPLIER 2
- void Interrogator_Hunt( qboolean visible, qboolean advance )
- {
- float distance, speed;
- vec3_t forward;
- Interrogator_PartsMove();
- NPC_FaceEnemy(qfalse);
- //If we're not supposed to stand still, pursue the player
- if ( NPCInfo->standTime < level.time )
- {
- // Only strafe when we can see the player
- if ( visible )
- {
- Interrogator_Strafe();
- if ( NPCInfo->standTime > level.time )
- {//successfully strafed
- return;
- }
- }
- }
- //If we don't want to advance, stop here
- if ( advance == qfalse )
- return;
- //Only try and navigate if the player is visible
- if ( visible == qfalse )
- {
- // Move towards our goal
- NPCInfo->goalEntity = NPC->enemy;
- NPCInfo->goalRadius = 12;
- NPC_MoveToGoal(qtrue);
- return;
- }
- else
- {
- VectorSubtract( NPC->enemy->currentOrigin, NPC->currentOrigin, forward );
- distance = VectorNormalize( forward );
- }
- speed = HUNTER_FORWARD_BASE_SPEED + HUNTER_FORWARD_MULTIPLIER * g_spskill->integer;
- VectorMA( NPC->client->ps.velocity, speed, forward, NPC->client->ps.velocity );
- }
- #define MIN_DISTANCE 64
- /*
- -------------------------
- Interrogator_Melee
- -------------------------
- */
- void Interrogator_Melee( qboolean visible, qboolean advance )
- {
- if ( TIMER_Done( NPC, "attackDelay" ) ) // Attack?
- {
- // Make sure that we are within the height range before we allow any damage to happen
- if ( NPC->currentOrigin[2] >= NPC->enemy->currentOrigin[2]+NPC->enemy->mins[2] && NPC->currentOrigin[2]+NPC->mins[2]+8 < NPC->enemy->currentOrigin[2]+NPC->enemy->maxs[2] )
- {
- TIMER_Set( NPC, "attackDelay", Q_irand( 500, 3000 ) );
- G_Damage( NPC->enemy, NPC, NPC, 0, 0, 2, DAMAGE_NO_KNOCKBACK, MOD_MELEE );
- NPC->enemy->client->poisonDamage = 18;
- NPC->enemy->client->poisonTime = level.time + 1000;
- // Drug our enemy up and do the wonky vision thing
- gentity_t *tent = G_TempEntity( NPC->enemy->currentOrigin, EV_DRUGGED );
- tent->owner = NPC->enemy;
- G_Sound( NPC, G_SoundIndex( "sound/chars/interrogator/misc/torture_droid_inject.mp3" ));
- }
- }
- if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
- {
- Interrogator_Hunt( visible, advance );
- }
- }
- /*
- -------------------------
- Interrogator_Attack
- -------------------------
- */
- void Interrogator_Attack( void )
- {
- // Always keep a good height off the ground
- Interrogator_MaintainHeight();
- //randomly talk
- if ( TIMER_Done(NPC,"patrolNoise") )
- {
- if (TIMER_Done(NPC,"angerNoise"))
- {
- G_SoundOnEnt( NPC, CHAN_AUTO, va("sound/chars/probe/misc/talk.wav", Q_irand(1, 3)) );
- TIMER_Set( NPC, "patrolNoise", Q_irand( 4000, 10000 ) );
- }
- }
- // If we don't have an enemy, just idle
- if ( NPC_CheckEnemyExt() == qfalse )
- {
- Interrogator_Idle();
- return;
- }
- // Rate our distance to the target, and our visibilty
- float distance = (int) DistanceHorizontalSquared( NPC->currentOrigin, NPC->enemy->currentOrigin );
- qboolean visible = NPC_ClearLOS( NPC->enemy );
- qboolean advance = (qboolean)(distance > MIN_DISTANCE*MIN_DISTANCE );
- if ( !visible )
- {
- advance = qtrue;
- }
- if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
- {
- Interrogator_Hunt( visible, advance );
- }
- NPC_FaceEnemy( qtrue );
- if (!advance)
- {
- Interrogator_Melee( visible, advance );
- }
- }
- /*
- -------------------------
- Interrogator_Idle
- -------------------------
- */
- void Interrogator_Idle( void )
- {
- if ( NPC_CheckPlayerTeamStealth() )
- {
- G_SoundOnEnt( NPC, CHAN_AUTO, "sound/chars/mark1/misc/anger.wav" );
- NPC_UpdateAngles( qtrue, qtrue );
- return;
- }
- Interrogator_MaintainHeight();
- NPC_BSIdle();
- }
- /*
- -------------------------
- NPC_BSInterrogator_Default
- -------------------------
- */
- void NPC_BSInterrogator_Default( void )
- {
- //NPC->e_DieFunc = dieF_Interrogator_die;
- if ( NPC->enemy )
- {
- Interrogator_Attack();
- }
- else
- {
- Interrogator_Idle();
- }
- }
|