00001 #include "b_local.h"
00002 #include "g_nav.h"
00003
00004 void Remote_Strafe( void );
00005
00006 #define VELOCITY_DECAY 0.85f
00007
00008
00009
00010 enum
00011 {
00012 LSTATE_NONE = 0,
00013 };
00014
00015 void Remote_Idle( void );
00016
00017 void NPC_Remote_Precache(void)
00018 {
00019 G_SoundIndex("sound/chars/remote/misc/fire.wav");
00020 G_SoundIndex( "sound/chars/remote/misc/hiss.wav");
00021 G_EffectIndex( "env/small_explode");
00022 }
00023
00024
00025
00026
00027
00028
00029 void NPC_Remote_Pain(gentity_t *self, gentity_t *attacker, int damage)
00030 {
00031 SaveNPCGlobals();
00032 SetNPCGlobals( self );
00033 Remote_Strafe();
00034 RestoreNPCGlobals();
00035
00036 NPC_Pain( self, attacker, damage );
00037 }
00038
00039
00040
00041
00042
00043
00044 void Remote_MaintainHeight( void )
00045 {
00046 float dif;
00047
00048
00049 NPC_UpdateAngles( qtrue, qtrue );
00050
00051 if ( NPC->client->ps.velocity[2] )
00052 {
00053 NPC->client->ps.velocity[2] *= VELOCITY_DECAY;
00054
00055 if ( fabs( NPC->client->ps.velocity[2] ) < 2 )
00056 {
00057 NPC->client->ps.velocity[2] = 0;
00058 }
00059 }
00060
00061 if ( NPC->enemy )
00062 {
00063 if (TIMER_Done( NPC, "heightChange"))
00064 {
00065 TIMER_Set( NPC,"heightChange",Q_irand( 1000, 3000 ));
00066
00067
00068 dif = (NPC->enemy->r.currentOrigin[2] + Q_irand( 0, NPC->enemy->r.maxs[2]+8 )) - NPC->r.currentOrigin[2];
00069
00070
00071 if ( fabs( dif ) > 2 )
00072 {
00073 if ( fabs( dif ) > 24 )
00074 {
00075 dif = ( dif < 0 ? -24 : 24 );
00076 }
00077 dif *= 10;
00078 NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2;
00079
00080 G_Sound( NPC, CHAN_AUTO, G_SoundIndex("sound/chars/remote/misc/hiss.wav"));
00081 }
00082 }
00083 }
00084 else
00085 {
00086 gentity_t *goal = NULL;
00087
00088 if ( NPCInfo->goalEntity )
00089 {
00090 goal = NPCInfo->goalEntity;
00091 }
00092 else
00093 {
00094 goal = NPCInfo->lastGoalEntity;
00095 }
00096 if ( goal )
00097 {
00098 dif = goal->r.currentOrigin[2] - NPC->r.currentOrigin[2];
00099
00100 if ( fabs( dif ) > 24 )
00101 {
00102 dif = ( dif < 0 ? -24 : 24 );
00103 NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2;
00104 }
00105 }
00106 }
00107
00108
00109 if ( NPC->client->ps.velocity[0] )
00110 {
00111 NPC->client->ps.velocity[0] *= VELOCITY_DECAY;
00112
00113 if ( fabs( NPC->client->ps.velocity[0] ) < 1 )
00114 {
00115 NPC->client->ps.velocity[0] = 0;
00116 }
00117 }
00118
00119 if ( NPC->client->ps.velocity[1] )
00120 {
00121 NPC->client->ps.velocity[1] *= VELOCITY_DECAY;
00122
00123 if ( fabs( NPC->client->ps.velocity[1] ) < 1 )
00124 {
00125 NPC->client->ps.velocity[1] = 0;
00126 }
00127 }
00128 }
00129
00130 #define REMOTE_STRAFE_VEL 256
00131 #define REMOTE_STRAFE_DIS 200
00132 #define REMOTE_UPWARD_PUSH 32
00133
00134
00135
00136
00137
00138
00139 void Remote_Strafe( void )
00140 {
00141 int dir;
00142 vec3_t end, right;
00143 trace_t tr;
00144
00145 AngleVectors( NPC->client->renderInfo.eyeAngles, NULL, right, NULL );
00146
00147
00148
00149 dir = ( rand() & 1 ) ? -1 : 1;
00150 VectorMA( NPC->r.currentOrigin, REMOTE_STRAFE_DIS * dir, right, end );
00151
00152 trap_Trace( &tr, NPC->r.currentOrigin, NULL, NULL, end, NPC->s.number, MASK_SOLID );
00153
00154
00155 if ( tr.fraction > 0.9f )
00156 {
00157 VectorMA( NPC->client->ps.velocity, REMOTE_STRAFE_VEL * dir, right, NPC->client->ps.velocity );
00158
00159 G_Sound( NPC, CHAN_AUTO, G_SoundIndex("sound/chars/remote/misc/hiss.wav"));
00160
00161
00162 NPC->client->ps.velocity[2] += REMOTE_UPWARD_PUSH;
00163
00164
00165
00166 NPCInfo->standTime = level.time + 3000 + random() * 500;
00167 }
00168 }
00169
00170 #define REMOTE_FORWARD_BASE_SPEED 10
00171 #define REMOTE_FORWARD_MULTIPLIER 5
00172
00173
00174
00175
00176
00177
00178 void Remote_Hunt( qboolean visible, qboolean advance, qboolean retreat )
00179 {
00180 float distance, speed;
00181 vec3_t forward;
00182
00183
00184 if ( NPCInfo->standTime < level.time )
00185 {
00186
00187 if ( visible )
00188 {
00189 Remote_Strafe();
00190 return;
00191 }
00192 }
00193
00194
00195 if ( advance == qfalse && visible == qtrue )
00196 return;
00197
00198
00199 if ( visible == qfalse )
00200 {
00201
00202 NPCInfo->goalEntity = NPC->enemy;
00203 NPCInfo->goalRadius = 12;
00204
00205
00206 if ( NPC_GetMoveDirection( forward, &distance ) == qfalse )
00207 return;
00208 }
00209 else
00210 {
00211 VectorSubtract( NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, forward );
00212 distance = VectorNormalize( forward );
00213 }
00214
00215 speed = REMOTE_FORWARD_BASE_SPEED + REMOTE_FORWARD_MULTIPLIER * g_spskill.integer;
00216 if ( retreat == qtrue )
00217 {
00218 speed *= -1;
00219 }
00220 VectorMA( NPC->client->ps.velocity, speed, forward, NPC->client->ps.velocity );
00221 }
00222
00223
00224
00225
00226
00227
00228
00229 void Remote_Fire (void)
00230 {
00231 vec3_t delta1, enemy_org1, muzzle1;
00232 vec3_t angleToEnemy1;
00233 static vec3_t forward, vright, up;
00234 static vec3_t muzzle;
00235 gentity_t *missile;
00236
00237 CalcEntitySpot( NPC->enemy, SPOT_HEAD, enemy_org1 );
00238 VectorCopy( NPC->r.currentOrigin, muzzle1 );
00239
00240 VectorSubtract (enemy_org1, muzzle1, delta1);
00241
00242 vectoangles ( delta1, angleToEnemy1 );
00243 AngleVectors (angleToEnemy1, forward, vright, up);
00244
00245 missile = CreateMissile( NPC->r.currentOrigin, forward, 1000, 10000, NPC, qfalse );
00246
00247 G_PlayEffectID( G_EffectIndex("bryar/muzzle_flash"), NPC->r.currentOrigin, forward );
00248
00249 missile->classname = "briar";
00250 missile->s.weapon = WP_BRYAR_PISTOL;
00251
00252 missile->damage = 10;
00253 missile->dflags = DAMAGE_DEATH_KNOCKBACK;
00254 missile->methodOfDeath = MOD_BRYAR_PISTOL;
00255 missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
00256
00257 }
00258
00259
00260
00261
00262
00263
00264 void Remote_Ranged( qboolean visible, qboolean advance, qboolean retreat )
00265 {
00266
00267 if ( TIMER_Done( NPC, "attackDelay" ) )
00268 {
00269 TIMER_Set( NPC, "attackDelay", Q_irand( 500, 3000 ) );
00270 Remote_Fire();
00271 }
00272
00273 if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
00274 {
00275 Remote_Hunt( visible, advance, retreat );
00276 }
00277 }
00278
00279 #define MIN_MELEE_RANGE 320
00280 #define MIN_MELEE_RANGE_SQR ( MIN_MELEE_RANGE * MIN_MELEE_RANGE )
00281
00282 #define MIN_DISTANCE 80
00283 #define MIN_DISTANCE_SQR ( MIN_DISTANCE * MIN_DISTANCE )
00284
00285
00286
00287
00288
00289
00290 void Remote_Attack( void )
00291 {
00292 float distance;
00293 qboolean visible;
00294 float idealDist;
00295 qboolean advance;
00296 qboolean retreat;
00297
00298 if ( TIMER_Done(NPC,"spin") )
00299 {
00300 TIMER_Set( NPC, "spin", Q_irand( 250, 1500 ) );
00301 NPCInfo->desiredYaw += Q_irand( -200, 200 );
00302 }
00303
00304 Remote_MaintainHeight();
00305
00306
00307 if ( NPC_CheckEnemyExt(qfalse) == qfalse )
00308 {
00309 Remote_Idle();
00310 return;
00311 }
00312
00313
00314 distance = (int) DistanceHorizontalSquared( NPC->r.currentOrigin, NPC->enemy->r.currentOrigin );
00315 visible = NPC_ClearLOS4( NPC->enemy );
00316 idealDist = MIN_DISTANCE_SQR+(MIN_DISTANCE_SQR*flrand( 0, 1 ));
00317 advance = (qboolean)(distance > idealDist*1.25);
00318 retreat = (qboolean)(distance < idealDist*0.75);
00319
00320
00321 if ( visible == qfalse )
00322 {
00323 if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
00324 {
00325 Remote_Hunt( visible, advance, retreat );
00326 return;
00327 }
00328 }
00329
00330 Remote_Ranged( visible, advance, retreat );
00331
00332 }
00333
00334
00335
00336
00337
00338
00339 void Remote_Idle( void )
00340 {
00341 Remote_MaintainHeight();
00342
00343 NPC_BSIdle();
00344 }
00345
00346
00347
00348
00349
00350
00351 void Remote_Patrol( void )
00352 {
00353 Remote_MaintainHeight();
00354
00355
00356 if (!NPC->enemy)
00357 {
00358 if ( UpdateGoal() )
00359 {
00360
00361 ucmd.buttons |= BUTTON_WALKING;
00362 NPC_MoveToGoal( qtrue );
00363 }
00364 }
00365
00366 NPC_UpdateAngles( qtrue, qtrue );
00367 }
00368
00369
00370
00371
00372
00373
00374
00375 void NPC_BSRemote_Default( void )
00376 {
00377 if ( NPC->enemy )
00378 {
00379 Remote_Attack();
00380 }
00381 else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
00382 {
00383 Remote_Patrol();
00384 }
00385 else
00386 {
00387 Remote_Idle();
00388 }
00389 }