00001
00002
00003
00004 #include "b_local.h"
00005 #include "anims.h"
00006 #include "say.h"
00007 #include "../icarus/Q3_Interface.h"
00008
00009 extern vec3_t playerMins;
00010 extern vec3_t playerMaxs;
00011
00012 extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath );
00013 extern void PM_SetTorsoAnimTimer( gentity_t *ent, int *torsoAnimTimer, int time );
00014 extern void PM_SetLegsAnimTimer( gentity_t *ent, int *legsAnimTimer, int time );
00015 extern void NPC_BSNoClip ( void );
00016 extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime );
00017 extern void NPC_ApplyRoff (void);
00018 extern void NPC_TempLookTarget ( gentity_t *self, int lookEntNum, int minLookTime, int maxLookTime );
00019 extern void NPC_CheckPlayerAim ( void );
00020 extern void NPC_CheckAllClear ( void );
00021 extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime );
00022 extern qboolean NPC_CheckLookTarget( gentity_t *self );
00023 extern void NPC_SetLookTarget( gentity_t *self, int entNum, int clearTime );
00024 extern void Mark1_dying( gentity_t *self );
00025 extern void NPC_BSCinematic( void );
00026 extern int GetTime ( int lastTime );
00027 extern void NPC_BSGM_Default( void );
00028 extern void NPC_CheckCharmed( void );
00029 extern qboolean Boba_Flying( gentity_t *self );
00030
00031 extern vmCvar_t g_saberRealisticCombat;
00032
00033
00034 gentity_t *NPC;
00035 gNPC_t *NPCInfo;
00036 gclient_t *client;
00037 usercmd_t ucmd;
00038 visibility_t enemyVisibility;
00039
00040 void NPC_SetAnim(gentity_t *ent,int type,int anim,int priority);
00041 void pitch_roll_for_slope( gentity_t *forwhom, vec3_t pass_slope );
00042 extern void GM_Dying( gentity_t *self );
00043
00044 extern int eventClearTime;
00045
00046 void CorpsePhysics( gentity_t *self )
00047 {
00048
00049 memset( &ucmd, 0, sizeof( ucmd ) );
00050 ClientThink( self->s.number, &ucmd );
00051
00052
00053
00054 if ( self->client->NPC_class == CLASS_GALAKMECH )
00055 {
00056 GM_Dying( self );
00057 }
00058
00059 if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE && !(self->s.eFlags&EF_DISINTEGRATION) )
00060 {
00061
00062 pitch_roll_for_slope( self, NULL );
00063 }
00064
00065 if ( eventClearTime == level.time + ALERT_CLEAR_TIME )
00066 {
00067 if ( !(self->client->ps.eFlags&EF_NODRAW) )
00068 {
00069 AddSightEvent( self->enemy, self->r.currentOrigin, 384, AEL_DISCOVERED, 0.0f );
00070 }
00071 }
00072
00073 if ( level.time - self->s.time > 3000 )
00074 {
00075 if ( g_dismember.integer < 11381138 && !g_saberRealisticCombat.integer )
00076 {
00077 if ( self->client->NPC_class != CLASS_PROTOCOL )
00078 {
00079
00080 }
00081 }
00082 }
00083
00084
00085 if (self->client->respawnTime < (level.time+500))
00086 {
00087
00088 if (self->client->ps.eFlags & EF_DISINTEGRATION)
00089 {
00090 self->r.contents = 0;
00091 }
00092 else if ((self->client->NPC_class != CLASS_MARK1) && (self->client->NPC_class != CLASS_INTERROGATOR))
00093 {
00094 self->r.contents = CONTENTS_CORPSE;
00095
00096 }
00097
00098 if ( self->message )
00099 {
00100 self->r.contents |= CONTENTS_TRIGGER;
00101 }
00102 }
00103 }
00104
00105
00106
00107
00108
00109
00110
00111
00112 #define REMOVE_DISTANCE 128
00113 #define REMOVE_DISTANCE_SQR (REMOVE_DISTANCE * REMOVE_DISTANCE)
00114
00115 void NPC_RemoveBody( gentity_t *self )
00116 {
00117 CorpsePhysics( self );
00118
00119 self->nextthink = level.time + FRAMETIME;
00120
00121 if ( self->NPC->nextBStateThink <= level.time )
00122 {
00123 trap_ICARUS_MaintainTaskManager(self->s.number);
00124 }
00125 self->NPC->nextBStateThink = level.time + FRAMETIME;
00126
00127 if ( self->message )
00128 {
00129 return;
00130 }
00131
00132
00133
00134 if (self->client->NPC_class == CLASS_MARK1)
00135 {
00136 Mark1_dying( self );
00137 }
00138
00139
00140 if ( self->client->NPC_class == CLASS_REMOTE
00141 || self->client->NPC_class == CLASS_SENTRY
00142 || self->client->NPC_class == CLASS_PROBE
00143 || self->client->NPC_class == CLASS_INTERROGATOR
00144 || self->client->NPC_class == CLASS_PROBE
00145 || self->client->NPC_class == CLASS_MARK2 )
00146 {
00147
00148 if (!trap_ICARUS_IsRunning(self->s.number))
00149 {
00150 if ( !self->activator || !self->activator->client || !(self->activator->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
00151 {
00152 G_FreeEntity( self );
00153 }
00154 }
00155 return;
00156 }
00157
00158
00159 self->r.maxs[2] = self->client->renderInfo.eyePoint[2] - self->r.currentOrigin[2] + 4;
00160 if ( self->r.maxs[2] < -8 )
00161 {
00162 self->r.maxs[2] = -8;
00163 }
00164
00165 if ( self->client->NPC_class == CLASS_GALAKMECH )
00166 {
00167 return;
00168 }
00169 if ( self->NPC && self->NPC->timeOfDeath <= level.time )
00170 {
00171 self->NPC->timeOfDeath = level.time + 1000;
00172
00174
00175
00176 if( self->client->playerTeam == NPCTEAM_ENEMY || self->client->NPC_class == CLASS_PROTOCOL )
00177 {
00178 self->nextthink = level.time + FRAMETIME;
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195 }
00196
00197
00198
00199
00200
00201
00202
00203 if ( self->enemy )
00204 {
00205
00206 if (!trap_ICARUS_IsRunning(self->s.number))
00207 {
00208 if ( !self->activator || !self->activator->client || !(self->activator->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
00209 {
00210 if ( self->client && self->client->ps.saberEntityNum > 0 && self->client->ps.saberEntityNum < ENTITYNUM_WORLD )
00211 {
00212 gentity_t *saberent = &g_entities[self->client->ps.saberEntityNum];
00213 if ( saberent )
00214 {
00215 G_FreeEntity( saberent );
00216 }
00217 }
00218 G_FreeEntity( self );
00219 }
00220 }
00221 }
00222 }
00223 }
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233 int BodyRemovalPadTime( gentity_t *ent )
00234 {
00235 int time;
00236
00237 if ( !ent || !ent->client )
00238 return 0;
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285 switch( ent->client->NPC_class )
00286 {
00287 case CLASS_MOUSE:
00288 case CLASS_GONK:
00289 case CLASS_R2D2:
00290 case CLASS_R5D2:
00291
00292 case CLASS_MARK1:
00293 case CLASS_MARK2:
00294 case CLASS_PROBE:
00295 case CLASS_SEEKER:
00296 case CLASS_REMOTE:
00297 case CLASS_SENTRY:
00298 case CLASS_INTERROGATOR:
00299 time = 0;
00300 break;
00301 default:
00302
00303
00304
00305 time = 10000;
00306 break;
00307
00308 }
00309
00310
00311 return time;
00312 }
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323 static void NPC_RemoveBodyEffect(void)
00324 {
00325
00326
00327
00328 if ( !NPC || !NPC->client || (NPC->s.eFlags & EF_NODRAW) )
00329 return;
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354 switch(NPC->client->NPC_class)
00355 {
00356 case CLASS_PROBE:
00357 case CLASS_SEEKER:
00358 case CLASS_REMOTE:
00359 case CLASS_SENTRY:
00360 case CLASS_GONK:
00361 case CLASS_R2D2:
00362 case CLASS_R5D2:
00363
00364 case CLASS_MARK1:
00365 case CLASS_MARK2:
00366 case CLASS_INTERROGATOR:
00367 case CLASS_ATST:
00368
00369
00370
00371
00372 break;
00373 default:
00374 break;
00375 }
00376
00377
00378 }
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395 void pitch_roll_for_slope( gentity_t *forwhom, vec3_t pass_slope )
00396 {
00397 vec3_t slope;
00398 vec3_t nvf, ovf, ovr, startspot, endspot, new_angles = { 0, 0, 0 };
00399 float pitch, mod, dot;
00400
00401
00402 if( !pass_slope || VectorCompare( vec3_origin, pass_slope ) )
00403 {
00404 trace_t trace;
00405
00406 VectorCopy( forwhom->r.currentOrigin, startspot );
00407 startspot[2] += forwhom->r.mins[2] + 4;
00408 VectorCopy( startspot, endspot );
00409 endspot[2] -= 300;
00410 trap_Trace( &trace, forwhom->r.currentOrigin, vec3_origin, vec3_origin, endspot, forwhom->s.number, MASK_SOLID );
00411
00412
00413
00414 if ( trace.fraction >= 1.0 )
00415 return;
00416
00417 if( !( &trace.plane ) )
00418 return;
00419
00420 if ( VectorCompare( vec3_origin, trace.plane.normal ) )
00421 return;
00422
00423 VectorCopy( trace.plane.normal, slope );
00424 }
00425 else
00426 {
00427 VectorCopy( pass_slope, slope );
00428 }
00429
00430
00431 AngleVectors( forwhom->r.currentAngles, ovf, ovr, NULL );
00432
00433 vectoangles( slope, new_angles );
00434 pitch = new_angles[PITCH] + 90;
00435 new_angles[ROLL] = new_angles[PITCH] = 0;
00436
00437 AngleVectors( new_angles, nvf, NULL, NULL );
00438
00439 mod = DotProduct( nvf, ovr );
00440
00441 if ( mod<0 )
00442 mod = -1;
00443 else
00444 mod = 1;
00445
00446 dot = DotProduct( nvf, ovf );
00447
00448 if ( forwhom->client )
00449 {
00450 float oldmins2;
00451
00452 forwhom->client->ps.viewangles[PITCH] = dot * pitch;
00453 forwhom->client->ps.viewangles[ROLL] = ((1-Q_fabs(dot)) * pitch * mod);
00454 oldmins2 = forwhom->r.mins[2];
00455 forwhom->r.mins[2] = -24 + 12 * fabs(forwhom->client->ps.viewangles[PITCH])/180.0f;
00456
00457 if ( oldmins2 > forwhom->r.mins[2] )
00458 {
00459
00460 forwhom->client->ps.origin[2] += (oldmins2 - forwhom->r.mins[2]);
00461 forwhom->r.currentOrigin[2] = forwhom->client->ps.origin[2];
00462 trap_LinkEntity( forwhom );
00463 }
00464 }
00465 else
00466 {
00467 forwhom->r.currentAngles[PITCH] = dot * pitch;
00468 forwhom->r.currentAngles[ROLL] = ((1-Q_fabs(dot)) * pitch * mod);
00469 }
00470 }
00471
00472
00473
00474
00475
00476
00477
00478 static void DeadThink ( void )
00479 {
00480 trace_t trace;
00481
00482
00483
00484
00485 NPC->r.maxs[2] = NPC->client->renderInfo.eyePoint[2] - NPC->r.currentOrigin[2] + 4;
00486 if ( NPC->r.maxs[2] < -8 )
00487 {
00488 NPC->r.maxs[2] = -8;
00489 }
00490 if ( VectorCompare( NPC->client->ps.velocity, vec3_origin ) )
00491 {
00492 if ( NPC->r.mins[0] > -32 )
00493 {
00494 NPC->r.mins[0] -= 1;
00495 trap_Trace (&trace, NPC->r.currentOrigin, NPC->r.mins, NPC->r.maxs, NPC->r.currentOrigin, NPC->s.number, NPC->clipmask );
00496 if ( trace.allsolid )
00497 {
00498 NPC->r.mins[0] += 1;
00499 }
00500 }
00501 if ( NPC->r.maxs[0] < 32 )
00502 {
00503 NPC->r.maxs[0] += 1;
00504 trap_Trace (&trace, NPC->r.currentOrigin, NPC->r.mins, NPC->r.maxs, NPC->r.currentOrigin, NPC->s.number, NPC->clipmask );
00505 if ( trace.allsolid )
00506 {
00507 NPC->r.maxs[0] -= 1;
00508 }
00509 }
00510 if ( NPC->r.mins[1] > -32 )
00511 {
00512 NPC->r.mins[1] -= 1;
00513 trap_Trace (&trace, NPC->r.currentOrigin, NPC->r.mins, NPC->r.maxs, NPC->r.currentOrigin, NPC->s.number, NPC->clipmask );
00514 if ( trace.allsolid )
00515 {
00516 NPC->r.mins[1] += 1;
00517 }
00518 }
00519 if ( NPC->r.maxs[1] < 32 )
00520 {
00521 NPC->r.maxs[1] += 1;
00522 trap_Trace (&trace, NPC->r.currentOrigin, NPC->r.mins, NPC->r.maxs, NPC->r.currentOrigin, NPC->s.number, NPC->clipmask );
00523 if ( trace.allsolid )
00524 {
00525 NPC->r.maxs[1] -= 1;
00526 }
00527 }
00528 }
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552 {
00553
00554 if ( level.time >= NPCInfo->timeOfDeath + BodyRemovalPadTime( NPC ) )
00555 {
00556 if ( NPC->client->ps.eFlags & EF_NODRAW )
00557 {
00558 if (!trap_ICARUS_IsRunning(NPC->s.number))
00559
00560 {
00561 NPC->think = G_FreeEntity;
00562 NPC->nextthink = level.time + FRAMETIME;
00563 }
00564 }
00565 else
00566 {
00567 class_t npc_class;
00568
00569
00570 NPC_RemoveBodyEffect();
00571
00572
00573 NPC->think = NPC_RemoveBody;
00574 NPC->nextthink = level.time + FRAMETIME;
00575
00576
00577
00578 npc_class = NPC->client->NPC_class;
00579
00580 if ( npc_class == CLASS_SEEKER || npc_class == CLASS_REMOTE || npc_class == CLASS_PROBE || npc_class == CLASS_MOUSE ||
00581 npc_class == CLASS_GONK || npc_class == CLASS_R2D2 || npc_class == CLASS_R5D2 ||
00582 npc_class == CLASS_MARK2 || npc_class == CLASS_SENTRY )
00583 {
00584 NPC->client->ps.eFlags |= EF_NODRAW;
00585 NPCInfo->timeOfDeath = level.time + FRAMETIME * 8;
00586 }
00587 else
00588 NPCInfo->timeOfDeath = level.time + FRAMETIME * 4;
00589 }
00590 return;
00591 }
00592 }
00593
00594
00595 if ( NPC->bounceCount < 0 && NPC->s.groundEntityNum >= 0 )
00596 {
00597
00598 int contents = NPC->bounceCount = trap_PointContents( NPC->r.currentOrigin, -1 );
00599
00600 if ( ( contents & CONTENTS_NODROP ) )
00601 {
00602 NPC->client->ps.eFlags |= EF_NODRAW;
00603 }
00604 }
00605
00606 CorpsePhysics( NPC );
00607 }
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617 void SetNPCGlobals( gentity_t *ent )
00618 {
00619 NPC = ent;
00620 NPCInfo = ent->NPC;
00621 client = ent->client;
00622 memset( &ucmd, 0, sizeof( usercmd_t ) );
00623 }
00624
00625 gentity_t *_saved_NPC;
00626 gNPC_t *_saved_NPCInfo;
00627 gclient_t *_saved_client;
00628 usercmd_t _saved_ucmd;
00629
00630 void SaveNPCGlobals(void)
00631 {
00632 _saved_NPC = NPC;
00633 _saved_NPCInfo = NPCInfo;
00634 _saved_client = client;
00635 memcpy( &_saved_ucmd, &ucmd, sizeof( usercmd_t ) );
00636 }
00637
00638 void RestoreNPCGlobals(void)
00639 {
00640 NPC = _saved_NPC;
00641 NPCInfo = _saved_NPCInfo;
00642 client = _saved_client;
00643 memcpy( &ucmd, &_saved_ucmd, sizeof( usercmd_t ) );
00644 }
00645
00646
00647 void ClearNPCGlobals( void )
00648 {
00649 NPC = NULL;
00650 NPCInfo = NULL;
00651 client = NULL;
00652 }
00653
00654
00655 extern qboolean showBBoxes;
00656 vec3_t NPCDEBUG_RED = {1.0, 0.0, 0.0};
00657 vec3_t NPCDEBUG_GREEN = {0.0, 1.0, 0.0};
00658 vec3_t NPCDEBUG_BLUE = {0.0, 0.0, 1.0};
00659 vec3_t NPCDEBUG_LIGHT_BLUE = {0.3f, 0.7f, 1.0};
00660 extern void G_Cube( vec3_t mins, vec3_t maxs, vec3_t color, float alpha );
00661 extern void G_Line( vec3_t start, vec3_t end, vec3_t color, float alpha );
00662 extern void G_Cylinder( vec3_t start, vec3_t end, float radius, vec3_t color );
00663
00664 void NPC_ShowDebugInfo (void)
00665 {
00666 if ( showBBoxes )
00667 {
00668 gentity_t *found = NULL;
00669 vec3_t mins, maxs;
00670
00671 while( (found = G_Find( found, FOFS(classname), "NPC" ) ) != NULL )
00672 {
00673 if ( trap_InPVS( found->r.currentOrigin, g_entities[0].r.currentOrigin ) )
00674 {
00675 VectorAdd( found->r.currentOrigin, found->r.mins, mins );
00676 VectorAdd( found->r.currentOrigin, found->r.maxs, maxs );
00677 G_Cube( mins, maxs, NPCDEBUG_RED, 0.25 );
00678 }
00679 }
00680 }
00681 }
00682
00683 void NPC_ApplyScriptFlags (void)
00684 {
00685 if ( NPCInfo->scriptFlags & SCF_CROUCHED )
00686 {
00687 if ( NPCInfo->charmedTime > level.time && (ucmd.forwardmove || ucmd.rightmove) )
00688 {
00689 }
00690 else
00691 {
00692 ucmd.upmove = -127;
00693 }
00694 }
00695
00696 if(NPCInfo->scriptFlags & SCF_RUNNING)
00697 {
00698 ucmd.buttons &= ~BUTTON_WALKING;
00699 }
00700 else if(NPCInfo->scriptFlags & SCF_WALKING)
00701 {
00702 if ( NPCInfo->charmedTime > level.time && (ucmd.forwardmove || ucmd.rightmove) )
00703 {
00704 }
00705 else
00706 {
00707 ucmd.buttons |= BUTTON_WALKING;
00708 }
00709 }
00710
00711
00712
00713
00714
00715
00716 if(NPCInfo->scriptFlags & SCF_LEAN_RIGHT)
00717 {
00718 ucmd.buttons |= BUTTON_USE;
00719 ucmd.rightmove = 127;
00720 ucmd.forwardmove = 0;
00721 ucmd.upmove = 0;
00722 }
00723 else if(NPCInfo->scriptFlags & SCF_LEAN_LEFT)
00724 {
00725 ucmd.buttons |= BUTTON_USE;
00726 ucmd.rightmove = -127;
00727 ucmd.forwardmove = 0;
00728 ucmd.upmove = 0;
00729 }
00730
00731 if ( (NPCInfo->scriptFlags & SCF_ALT_FIRE) && (ucmd.buttons & BUTTON_ATTACK) )
00732 {
00733 ucmd.buttons |= BUTTON_ALT_ATTACK;
00734 }
00735 }
00736
00737 void Q3_DebugPrint( int level, const char *format, ... );
00738 void NPC_HandleAIFlags (void)
00739 {
00740
00741 if ( NPCInfo->aiFlags & NPCAI_LOST )
00742 {
00743
00744 NPCInfo->aiFlags &= ~NPCAI_LOST;
00745
00746
00747
00748
00749
00750
00751
00752
00753 if ( NPCInfo->goalEntity && NPCInfo->goalEntity == NPC->enemy )
00754 {
00755
00756 NPC_LostEnemyDecideChase();
00757 }
00758 }
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811 if ( NPCInfo->greetingDebounceTime && NPCInfo->greetingDebounceTime < level.time )
00812 {
00813 G_AddVoiceEvent( NPC, Q_irand(EV_VICTORY1, EV_VICTORY3), Q_irand( 2000, 4000 ) );
00814 NPCInfo->greetingDebounceTime = 0;
00815 }
00816
00817 if ( NPCInfo->ffireCount > 0 )
00818 {
00819 if ( NPCInfo->ffireFadeDebounce < level.time )
00820 {
00821 NPCInfo->ffireCount--;
00822
00823 NPCInfo->ffireFadeDebounce = level.time + 3000;
00824 }
00825 }
00826 if ( d_patched.integer )
00827 {
00828 if ( NPCInfo->consecutiveBlockedMoves > 20 )
00829 {
00830 NPCInfo->consecutiveBlockedMoves = 0;
00831 }
00832 }
00833 }
00834
00835 void NPC_AvoidWallsAndCliffs (void)
00836 {
00837
00838 }
00839
00840 void NPC_CheckAttackScript(void)
00841 {
00842 if(!(ucmd.buttons & BUTTON_ATTACK))
00843 {
00844 return;
00845 }
00846
00847 G_ActivateBehavior(NPC, BSET_ATTACK);
00848 }
00849
00850 float NPC_MaxDistSquaredForWeapon (void);
00851 void NPC_CheckAttackHold(void)
00852 {
00853 vec3_t vec;
00854
00855
00856 if ( !NPC->enemy )
00857 {
00858 NPCInfo->attackHoldTime = 0;
00859 return;
00860 }
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894 {
00895 VectorSubtract(NPC->enemy->r.currentOrigin, NPC->r.currentOrigin, vec);
00896 if( VectorLengthSquared(vec) > NPC_MaxDistSquaredForWeapon() )
00897 {
00898 NPCInfo->attackHoldTime = 0;
00899 }
00900 else if( NPCInfo->attackHoldTime && NPCInfo->attackHoldTime > level.time )
00901 {
00902 ucmd.buttons |= BUTTON_ATTACK;
00903 }
00904 else if ( ( NPCInfo->attackHold ) && ( ucmd.buttons & BUTTON_ATTACK ) )
00905 {
00906 NPCInfo->attackHoldTime = level.time + NPCInfo->attackHold;
00907 }
00908 else
00909 {
00910 NPCInfo->attackHoldTime = 0;
00911 }
00912 }
00913 }
00914
00915
00916
00917
00918
00919
00920 void NPC_KeepCurrentFacing(void)
00921 {
00922 if(!ucmd.angles[YAW])
00923 {
00924 ucmd.angles[YAW] = ANGLE2SHORT( client->ps.viewangles[YAW] ) - client->ps.delta_angles[YAW];
00925 }
00926
00927 if(!ucmd.angles[PITCH])
00928 {
00929 ucmd.angles[PITCH] = ANGLE2SHORT( client->ps.viewangles[PITCH] ) - client->ps.delta_angles[PITCH];
00930 }
00931 }
00932
00933
00934
00935
00936
00937
00938
00939 void NPC_BehaviorSet_Charmed( int bState )
00940 {
00941 switch( bState )
00942 {
00943 case BS_FOLLOW_LEADER:
00944 NPC_BSFollowLeader();
00945 break;
00946 case BS_REMOVE:
00947 NPC_BSRemove();
00948 break;
00949 case BS_SEARCH:
00950 NPC_BSSearch();
00951 break;
00952 case BS_WANDER:
00953 NPC_BSWander();
00954 break;
00955 case BS_FLEE:
00956 NPC_BSFlee();
00957 break;
00958 default:
00959 case BS_DEFAULT:
00960 NPC_BSDefault();
00961 break;
00962 }
00963 }
00964
00965
00966
00967
00968
00969
00970 void NPC_BehaviorSet_Default( int bState )
00971 {
00972 switch( bState )
00973 {
00974 case BS_ADVANCE_FIGHT:
00975 NPC_BSAdvanceFight ();
00976 break;
00977 case BS_SLEEP:
00978 NPC_BSSleep ();
00979 break;
00980 case BS_FOLLOW_LEADER:
00981 NPC_BSFollowLeader();
00982 break;
00983 case BS_JUMP:
00984 NPC_BSJump();
00985 break;
00986 case BS_REMOVE:
00987 NPC_BSRemove();
00988 break;
00989 case BS_SEARCH:
00990 NPC_BSSearch();
00991 break;
00992 case BS_NOCLIP:
00993 NPC_BSNoClip();
00994 break;
00995 case BS_WANDER:
00996 NPC_BSWander();
00997 break;
00998 case BS_FLEE:
00999 NPC_BSFlee();
01000 break;
01001 case BS_WAIT:
01002 NPC_BSWait();
01003 break;
01004 case BS_CINEMATIC:
01005 NPC_BSCinematic();
01006 break;
01007 default:
01008 case BS_DEFAULT:
01009 NPC_BSDefault();
01010 break;
01011 }
01012 }
01013
01014
01015
01016
01017
01018
01019 void NPC_BehaviorSet_Interrogator( int bState )
01020 {
01021 switch( bState )
01022 {
01023 case BS_STAND_GUARD:
01024 case BS_PATROL:
01025 case BS_STAND_AND_SHOOT:
01026 case BS_HUNT_AND_KILL:
01027 case BS_DEFAULT:
01028 NPC_BSInterrogator_Default();
01029 break;
01030 default:
01031 NPC_BehaviorSet_Default( bState );
01032 break;
01033 }
01034 }
01035
01036 void NPC_BSImperialProbe_Attack( void );
01037 void NPC_BSImperialProbe_Patrol( void );
01038 void NPC_BSImperialProbe_Wait(void);
01039
01040
01041
01042
01043
01044
01045 void NPC_BehaviorSet_ImperialProbe( int bState )
01046 {
01047 switch( bState )
01048 {
01049 case BS_STAND_GUARD:
01050 case BS_PATROL:
01051 case BS_STAND_AND_SHOOT:
01052 case BS_HUNT_AND_KILL:
01053 case BS_DEFAULT:
01054 NPC_BSImperialProbe_Default();
01055 break;
01056 default:
01057 NPC_BehaviorSet_Default( bState );
01058 break;
01059 }
01060 }
01061
01062
01063 void NPC_BSSeeker_Default( void );
01064
01065
01066
01067
01068
01069
01070 void NPC_BehaviorSet_Seeker( int bState )
01071 {
01072 switch( bState )
01073 {
01074 case BS_STAND_GUARD:
01075 case BS_PATROL:
01076 case BS_STAND_AND_SHOOT:
01077 case BS_HUNT_AND_KILL:
01078 case BS_DEFAULT:
01079 NPC_BSSeeker_Default();
01080 break;
01081 default:
01082 NPC_BehaviorSet_Default( bState );
01083 break;
01084 }
01085 }
01086
01087 void NPC_BSRemote_Default( void );
01088
01089
01090
01091
01092
01093
01094 void NPC_BehaviorSet_Remote( int bState )
01095 {
01096 NPC_BSRemote_Default();
01097 }
01098
01099 void NPC_BSSentry_Default( void );
01100
01101
01102
01103
01104
01105
01106 void NPC_BehaviorSet_Sentry( int bState )
01107 {
01108 switch( bState )
01109 {
01110 case BS_STAND_GUARD:
01111 case BS_PATROL:
01112 case BS_STAND_AND_SHOOT:
01113 case BS_HUNT_AND_KILL:
01114 case BS_DEFAULT:
01115 NPC_BSSentry_Default();
01116 break;
01117 default:
01118 NPC_BehaviorSet_Default( bState );
01119 break;
01120 }
01121 }
01122
01123
01124
01125
01126
01127
01128 void NPC_BehaviorSet_Grenadier( int bState )
01129 {
01130 switch( bState )
01131 {
01132 case BS_STAND_GUARD:
01133 case BS_PATROL:
01134 case BS_STAND_AND_SHOOT:
01135 case BS_HUNT_AND_KILL:
01136 case BS_DEFAULT:
01137 NPC_BSGrenadier_Default();
01138 break;
01139
01140 default:
01141 NPC_BehaviorSet_Default( bState );
01142 break;
01143 }
01144 }
01145
01146
01147
01148
01149
01150 void NPC_BehaviorSet_Sniper( int bState )
01151 {
01152 switch( bState )
01153 {
01154 case BS_STAND_GUARD:
01155 case BS_PATROL:
01156 case BS_STAND_AND_SHOOT:
01157 case BS_HUNT_AND_KILL:
01158 case BS_DEFAULT:
01159 NPC_BSSniper_Default();
01160 break;
01161
01162 default:
01163 NPC_BehaviorSet_Default( bState );
01164 break;
01165 }
01166 }
01167
01168
01169
01170
01171
01172
01173 void NPC_BehaviorSet_Stormtrooper( int bState )
01174 {
01175 switch( bState )
01176 {
01177 case BS_STAND_GUARD:
01178 case BS_PATROL:
01179 case BS_STAND_AND_SHOOT:
01180 case BS_HUNT_AND_KILL:
01181 case BS_DEFAULT:
01182 NPC_BSST_Default();
01183 break;
01184
01185 case BS_INVESTIGATE:
01186 NPC_BSST_Investigate();
01187 break;
01188
01189 case BS_SLEEP:
01190 NPC_BSST_Sleep();
01191 break;
01192
01193 default:
01194 NPC_BehaviorSet_Default( bState );
01195 break;
01196 }
01197 }
01198
01199
01200
01201
01202
01203
01204
01205 void NPC_BehaviorSet_Jedi( int bState )
01206 {
01207 switch( bState )
01208 {
01209 case BS_STAND_GUARD:
01210 case BS_PATROL:
01211 case BS_STAND_AND_SHOOT:
01212 case BS_HUNT_AND_KILL:
01213 case BS_DEFAULT:
01214 NPC_BSJedi_Default();
01215 break;
01216
01217 case BS_FOLLOW_LEADER:
01218 NPC_BSJedi_FollowLeader();
01219 break;
01220
01221 default:
01222 NPC_BehaviorSet_Default( bState );
01223 break;
01224 }
01225 }
01226
01227
01228
01229
01230
01231
01232 void NPC_BehaviorSet_Droid( int bState )
01233 {
01234 switch( bState )
01235 {
01236 case BS_DEFAULT:
01237 case BS_STAND_GUARD:
01238 case BS_PATROL:
01239 NPC_BSDroid_Default();
01240 break;
01241 default:
01242 NPC_BehaviorSet_Default( bState );
01243 break;
01244 }
01245 }
01246
01247
01248
01249
01250
01251
01252 void NPC_BehaviorSet_Mark1( int bState )
01253 {
01254 switch( bState )
01255 {
01256 case BS_DEFAULT:
01257 case BS_STAND_GUARD:
01258 case BS_PATROL:
01259 NPC_BSMark1_Default();
01260 break;
01261 default:
01262 NPC_BehaviorSet_Default( bState );
01263 break;
01264 }
01265 }
01266
01267
01268
01269
01270
01271
01272 void NPC_BehaviorSet_Mark2( int bState )
01273 {
01274 switch( bState )
01275 {
01276 case BS_DEFAULT:
01277 case BS_PATROL:
01278 case BS_STAND_AND_SHOOT:
01279 case BS_HUNT_AND_KILL:
01280 NPC_BSMark2_Default();
01281 break;
01282 default:
01283 NPC_BehaviorSet_Default( bState );
01284 break;
01285 }
01286 }
01287
01288
01289
01290
01291
01292
01293 void NPC_BehaviorSet_ATST( int bState )
01294 {
01295 switch( bState )
01296 {
01297 case BS_DEFAULT:
01298 case BS_PATROL:
01299 case BS_STAND_AND_SHOOT:
01300 case BS_HUNT_AND_KILL:
01301 NPC_BSATST_Default();
01302 break;
01303 default:
01304 NPC_BehaviorSet_Default( bState );
01305 break;
01306 }
01307 }
01308
01309
01310
01311
01312
01313
01314 void NPC_BehaviorSet_MineMonster( int bState )
01315 {
01316 switch( bState )
01317 {
01318 case BS_STAND_GUARD:
01319 case BS_PATROL:
01320 case BS_STAND_AND_SHOOT:
01321 case BS_HUNT_AND_KILL:
01322 case BS_DEFAULT:
01323 NPC_BSMineMonster_Default();
01324 break;
01325 default:
01326 NPC_BehaviorSet_Default( bState );
01327 break;
01328 }
01329 }
01330
01331
01332
01333
01334
01335
01336 void NPC_BehaviorSet_Howler( int bState )
01337 {
01338 switch( bState )
01339 {
01340 case BS_STAND_GUARD:
01341 case BS_PATROL:
01342 case BS_STAND_AND_SHOOT:
01343 case BS_HUNT_AND_KILL:
01344 case BS_DEFAULT:
01345 NPC_BSHowler_Default();
01346 break;
01347 default:
01348 NPC_BehaviorSet_Default( bState );
01349 break;
01350 }
01351 }
01352
01353
01354
01355
01356
01357
01358 void NPC_BehaviorSet_Rancor( int bState )
01359 {
01360 switch( bState )
01361 {
01362 case BS_STAND_GUARD:
01363 case BS_PATROL:
01364 case BS_STAND_AND_SHOOT:
01365 case BS_HUNT_AND_KILL:
01366 case BS_DEFAULT:
01367 NPC_BSRancor_Default();
01368 break;
01369 default:
01370 NPC_BehaviorSet_Default( bState );
01371 break;
01372 }
01373 }
01374
01375
01376
01377
01378
01379
01380 extern void NPC_BSEmplaced( void );
01381 extern qboolean NPC_CheckSurrender( void );
01382 extern void Boba_FlyStop( gentity_t *self );
01383 extern void NPC_BSWampa_Default( void );
01384 void NPC_RunBehavior( int team, int bState )
01385 {
01386 qboolean dontSetAim = qfalse;
01387
01388 if (NPC->s.NPC_class == CLASS_VEHICLE &&
01389 NPC->m_pVehicle)
01390 {
01391 return;
01392 }
01393
01394 if ( bState == BS_CINEMATIC )
01395 {
01396 NPC_BSCinematic();
01397 }
01398 else if ( NPC->client->ps.weapon == WP_EMPLACED_GUN )
01399 {
01400 NPC_BSEmplaced();
01401 NPC_CheckCharmed();
01402 return;
01403 }
01404 else if ( NPC->client->ps.weapon == WP_SABER )
01405 {
01406 NPC_BehaviorSet_Jedi( bState );
01407 dontSetAim = qtrue;
01408 }
01409 else if ( NPC->client->NPC_class == CLASS_WAMPA )
01410 {
01411 NPC_BSWampa_Default();
01412 }
01413 else if ( NPC->client->NPC_class == CLASS_RANCOR )
01414 {
01415 NPC_BehaviorSet_Rancor( bState );
01416 }
01417 else if ( NPC->client->NPC_class == CLASS_REMOTE )
01418 {
01419 NPC_BehaviorSet_Remote( bState );
01420 }
01421 else if ( NPC->client->NPC_class == CLASS_SEEKER )
01422 {
01423 NPC_BehaviorSet_Seeker( bState );
01424 }
01425 else if ( NPC->client->NPC_class == CLASS_BOBAFETT )
01426 {
01427 if ( Boba_Flying( NPC ) )
01428 {
01429 NPC_BehaviorSet_Seeker(bState);
01430 }
01431 else
01432 {
01433 NPC_BehaviorSet_Jedi( bState );
01434 }
01435 dontSetAim = qtrue;
01436 }
01437 else if ( NPCInfo->scriptFlags & SCF_FORCED_MARCH )
01438 {
01439 NPC_BSDefault();
01440 }
01441 else
01442 {
01443 switch( team )
01444 {
01445
01446
01447
01448
01449
01450
01451
01452 case NPCTEAM_ENEMY:
01453
01454 switch( NPC->client->NPC_class)
01455 {
01456 case CLASS_ATST:
01457 NPC_BehaviorSet_ATST( bState );
01458 return;
01459 case CLASS_PROBE:
01460 NPC_BehaviorSet_ImperialProbe(bState);
01461 return;
01462 case CLASS_REMOTE:
01463 NPC_BehaviorSet_Remote( bState );
01464 return;
01465 case CLASS_SENTRY:
01466 NPC_BehaviorSet_Sentry(bState);
01467 return;
01468 case CLASS_INTERROGATOR:
01469 NPC_BehaviorSet_Interrogator( bState );
01470 return;
01471 case CLASS_MINEMONSTER:
01472 NPC_BehaviorSet_MineMonster( bState );
01473 return;
01474 case CLASS_HOWLER:
01475 NPC_BehaviorSet_Howler( bState );
01476 return;
01477 case CLASS_MARK1:
01478 NPC_BehaviorSet_Mark1( bState );
01479 return;
01480 case CLASS_MARK2:
01481 NPC_BehaviorSet_Mark2( bState );
01482 return;
01483 case CLASS_GALAKMECH:
01484 NPC_BSGM_Default();
01485 return;
01486
01487 }
01488
01489 if ( NPC->enemy && NPC->s.weapon == WP_NONE && bState != BS_HUNT_AND_KILL && !trap_ICARUS_TaskIDPending( NPC, TID_MOVE_NAV ) )
01490 {
01491 if ( bState != BS_FLEE )
01492 {
01493 NPC_StartFlee( NPC->enemy, NPC->enemy->r.currentOrigin, AEL_DANGER_GREAT, 5000, 10000 );
01494 }
01495 else
01496 {
01497 NPC_BSFlee();
01498 }
01499 return;
01500 }
01501 if ( NPC->client->ps.weapon == WP_SABER )
01502 {
01503 NPC_BehaviorSet_Default( bState );
01504 return;
01505 }
01506 if ( NPC->client->ps.weapon == WP_DISRUPTOR && (NPCInfo->scriptFlags & SCF_ALT_FIRE) )
01507 {
01508 NPC_BehaviorSet_Sniper( bState );
01509 return;
01510 }
01511 if ( NPC->client->ps.weapon == WP_THERMAL || NPC->client->ps.weapon == WP_STUN_BATON )
01512 {
01513 NPC_BehaviorSet_Grenadier( bState );
01514 return;
01515 }
01516 if ( NPC_CheckSurrender() )
01517 {
01518 return;
01519 }
01520 NPC_BehaviorSet_Stormtrooper( bState );
01521 break;
01522
01523 case NPCTEAM_NEUTRAL:
01524
01525
01526 if ( NPC->client->NPC_class == CLASS_PROTOCOL || NPC->client->NPC_class == CLASS_UGNAUGHT ||
01527 NPC->client->NPC_class == CLASS_JAWA)
01528 {
01529 NPC_BehaviorSet_Default(bState);
01530 }
01531 else if ( NPC->client->NPC_class == CLASS_VEHICLE )
01532 {
01533
01534 NPC_UpdateAngles( qtrue, qtrue );
01535 }
01536 else
01537 {
01538
01539 NPC_BehaviorSet_Droid( bState );
01540 }
01541 break;
01542
01543 default:
01544 if ( NPC->client->NPC_class == CLASS_SEEKER )
01545 {
01546 NPC_BehaviorSet_Seeker(bState);
01547 }
01548 else
01549 {
01550 if ( NPCInfo->charmedTime > level.time )
01551 {
01552 NPC_BehaviorSet_Charmed( bState );
01553 }
01554 else
01555 {
01556 NPC_BehaviorSet_Default( bState );
01557 }
01558 NPC_CheckCharmed();
01559 dontSetAim = qtrue;
01560 }
01561 break;
01562 }
01563 }
01564 }
01565
01566
01567
01568
01569
01570
01571
01572
01573
01574
01575
01576 void NPC_ExecuteBState ( gentity_t *self)
01577 {
01578 bState_t bState;
01579
01580 NPC_HandleAIFlags();
01581
01582
01583
01584 if(NPC->delayScriptTime && NPC->delayScriptTime <= level.time)
01585 {
01586 G_ActivateBehavior( NPC, BSET_DELAYED);
01587 NPC->delayScriptTime = 0;
01588 }
01589
01590
01591 NPCInfo->combatMove = qfalse;
01592
01593
01594 if(NPCInfo->tempBehavior)
01595 {
01596 bState = NPCInfo->tempBehavior;
01597 }
01598 else
01599 {
01600 if(!NPCInfo->behaviorState)
01601 NPCInfo->behaviorState = NPCInfo->defaultBehavior;
01602
01603 bState = NPCInfo->behaviorState;
01604 }
01605
01606
01607 NPC_RunBehavior( self->client->playerTeam, bState );
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628 if ( NPC->enemy )
01629 {
01630 if ( !NPC->enemy->inuse )
01631 {
01632 G_ClearEnemy( NPC );
01633 }
01634 }
01635
01636 if ( NPC->client->ps.saberLockTime && NPC->client->ps.saberLockEnemy != ENTITYNUM_NONE )
01637 {
01638 NPC_SetLookTarget( NPC, NPC->client->ps.saberLockEnemy, level.time+1000 );
01639 }
01640 else if ( !NPC_CheckLookTarget( NPC ) )
01641 {
01642 if ( NPC->enemy )
01643 {
01644 NPC_SetLookTarget( NPC, NPC->enemy->s.number, 0 );
01645 }
01646 }
01647
01648 if ( NPC->enemy )
01649 {
01650 if(NPC->enemy->flags & FL_DONT_SHOOT)
01651 {
01652 ucmd.buttons &= ~BUTTON_ATTACK;
01653 ucmd.buttons &= ~BUTTON_ALT_ATTACK;
01654 }
01655 else if ( NPC->client->playerTeam != NPCTEAM_ENEMY && NPC->enemy->NPC && (NPC->enemy->NPC->surrenderTime > level.time || (NPC->enemy->NPC->scriptFlags&SCF_FORCED_MARCH)) )
01656 {
01657 ucmd.buttons &= ~BUTTON_ATTACK;
01658 ucmd.buttons &= ~BUTTON_ALT_ATTACK;
01659 }
01660
01661 if(client->ps.weaponstate == WEAPON_IDLE)
01662 {
01663 client->ps.weaponstate = WEAPON_READY;
01664 }
01665 }
01666 else
01667 {
01668 if(client->ps.weaponstate == WEAPON_READY)
01669 {
01670 client->ps.weaponstate = WEAPON_IDLE;
01671 }
01672 }
01673
01674 if(!(ucmd.buttons & BUTTON_ATTACK) && NPC->attackDebounceTime > level.time)
01675 {
01676 if(client->ps.weapon == WP_SABER )
01677 {
01678 NPC_SetAnim(NPC,SETANIM_TORSO,TORSO_WEAPONREADY1,SETANIM_FLAG_NORMAL);
01679 }
01680 else if(client->ps.weapon == WP_BRYAR_PISTOL)
01681 {
01682 NPC_SetAnim(NPC,SETANIM_TORSO,TORSO_WEAPONREADY3,SETANIM_FLAG_NORMAL);
01683 }
01684
01685
01686
01687
01688
01689
01690 }
01691 else if ( !NPC->enemy )
01692 {
01693
01694 {
01695 if( NPC->s.torsoAnim == TORSO_WEAPONREADY1 || NPC->s.torsoAnim == TORSO_WEAPONREADY3 )
01696 {
01697 NPC_SetAnim(NPC,SETANIM_TORSO,TORSO_WEAPONIDLE3,SETANIM_FLAG_NORMAL);
01698 }
01699 }
01700 }
01701
01702 NPC_CheckAttackHold();
01703 NPC_ApplyScriptFlags();
01704
01705
01706 NPC_AvoidWallsAndCliffs();
01707
01708
01709
01710 ucmd.serverTime = level.time - 50;
01711 memcpy( &NPCInfo->last_ucmd, &ucmd, sizeof( usercmd_t ) );
01712 if ( !NPCInfo->attackHoldTime )
01713 {
01714 NPCInfo->last_ucmd.buttons &= ~(BUTTON_ATTACK|BUTTON_ALT_ATTACK);
01715 }
01716
01717 NPC_CheckAttackScript();
01718 NPC_KeepCurrentFacing();
01719
01720 if ( !NPC->next_roff_time || NPC->next_roff_time < level.time )
01721 {
01722 ClientThink( NPC->s.number, &ucmd );
01723 }
01724 else
01725 {
01726 NPC_ApplyRoff();
01727 }
01728
01729
01730 NPCInfo->touchedByPlayer = NULL;
01731
01732 NPC_CheckPlayerAim();
01733 NPC_CheckAllClear();
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762 }
01763
01764 void NPC_CheckInSolid(void)
01765 {
01766 trace_t trace;
01767 vec3_t point;
01768 VectorCopy(NPC->r.currentOrigin, point);
01769 point[2] -= 0.25;
01770
01771 trap_Trace(&trace, NPC->r.currentOrigin, NPC->r.mins, NPC->r.maxs, point, NPC->s.number, NPC->clipmask);
01772 if(!trace.startsolid && !trace.allsolid)
01773 {
01774 VectorCopy(NPC->r.currentOrigin, NPCInfo->lastClearOrigin);
01775 }
01776 else
01777 {
01778 if(VectorLengthSquared(NPCInfo->lastClearOrigin))
01779 {
01780
01781 G_SetOrigin(NPC, NPCInfo->lastClearOrigin);
01782 trap_LinkEntity(NPC);
01783 }
01784 }
01785 }
01786
01787 void G_DroidSounds( gentity_t *self )
01788 {
01789 if ( self->client )
01790 {
01791 if ( TIMER_Done( self, "patrolNoise" ) && !Q_irand( 0, 20 ) )
01792 {
01793 switch( self->client->NPC_class )
01794 {
01795 case CLASS_R2D2:
01796 G_SoundOnEnt(self, CHAN_AUTO, va("sound/chars/r2d2/misc/r2d2talk0%d.wav",Q_irand(1, 3)) );
01797 break;
01798 case CLASS_R5D2:
01799 G_SoundOnEnt(self, CHAN_AUTO, va("sound/chars/r5d2/misc/r5talk%d.wav",Q_irand(1, 4)) );
01800 break;
01801 case CLASS_PROBE:
01802 G_SoundOnEnt(self, CHAN_AUTO, va("sound/chars/probe/misc/probetalk%d.wav",Q_irand(1, 3)) );
01803 break;
01804 case CLASS_MOUSE:
01805 G_SoundOnEnt(self, CHAN_AUTO, va("sound/chars/mouse/misc/mousego%d.wav",Q_irand(1, 3)) );
01806 break;
01807 case CLASS_GONK:
01808 G_SoundOnEnt(self, CHAN_AUTO, va("sound/chars/gonk/misc/gonktalk%d.wav",Q_irand(1, 2)) );
01809 break;
01810 }
01811 TIMER_Set( self, "patrolNoise", Q_irand( 2000, 4000 ) );
01812 }
01813 }
01814 }
01815
01816
01817
01818
01819
01820
01821
01822
01823 #if AI_TIMERS
01824 extern int AITime;
01825 #endif// AI_TIMERS
01826 void NPC_Think ( gentity_t *self)
01827 {
01828 vec3_t oldMoveDir;
01829 int i = 0;
01830 gentity_t *player;
01831
01832 self->nextthink = level.time + FRAMETIME;
01833
01834 SetNPCGlobals( self );
01835
01836 memset( &ucmd, 0, sizeof( ucmd ) );
01837
01838 VectorCopy( self->client->ps.moveDir, oldMoveDir );
01839 if (self->s.NPC_class != CLASS_VEHICLE)
01840 {
01841 VectorClear( self->client->ps.moveDir );
01842 }
01843
01844 if(!self || !self->NPC || !self->client)
01845 {
01846 return;
01847 }
01848
01849
01850
01851 if ( self->health <= 0 )
01852 {
01853 DeadThink();
01854 if ( NPCInfo->nextBStateThink <= level.time )
01855 {
01856 trap_ICARUS_MaintainTaskManager(self->s.number);
01857 }
01858 VectorCopy(self->r.currentOrigin, self->client->ps.origin);
01859 return;
01860 }
01861
01862
01863 if ( debugNPCFreeze.value || (NPC->r.svFlags&SVF_ICARUS_FREEZE) )
01864 {
01865 NPC_UpdateAngles( qtrue, qtrue );
01866 ClientThink(self->s.number, &ucmd);
01867
01868 VectorCopy(self->r.currentOrigin, self->client->ps.origin);
01869 return;
01870 }
01871
01872 self->nextthink = level.time + FRAMETIME/2;
01873
01874
01875 while (i < MAX_CLIENTS)
01876 {
01877 player = &g_entities[i];
01878
01879 if (player->inuse && player->client && player->client->sess.sessionTeam != TEAM_SPECTATOR &&
01880 !(player->client->ps.pm_flags & PMF_FOLLOW))
01881 {
01882
01883 if (0)
01884 {
01885 G_DroidSounds( self );
01886
01887
01888
01889 NPCInfo->last_ucmd.serverTime = level.time - 50;
01890 ClientThink( NPC->s.number, &ucmd );
01891
01892 VectorCopy(self->r.currentOrigin, self->client->ps.origin);
01893 return;
01894 }
01895 }
01896 i++;
01897 }
01898
01899 if ( self->client->NPC_class == CLASS_VEHICLE)
01900 {
01901 if (self->client->ps.m_iVehicleNum)
01902 {
01903
01904 trap_ICARUS_MaintainTaskManager(self->s.number);
01905 return;
01906 }
01907 else
01908 {
01909 VectorClear(self->client->ps.moveDir);
01910 self->client->pers.cmd.forwardmove = 0;
01911 self->client->pers.cmd.rightmove = 0;
01912 self->client->pers.cmd.upmove = 0;
01913 self->client->pers.cmd.buttons = 0;
01914 memcpy(&self->m_pVehicle->m_ucmd, &self->client->pers.cmd, sizeof(usercmd_t));
01915 }
01916 }
01917 else if ( NPC->s.m_iVehicleNum )
01918 {
01919 G_DroidSounds( self );
01920 }
01921
01922 if ( NPCInfo->nextBStateThink <= level.time
01923 && !NPC->s.m_iVehicleNum )
01924 {
01925 #if AI_TIMERS
01926 int startTime = GetTime(0);
01927 #endif// AI_TIMERS
01928 if ( NPC->s.eType != ET_NPC )
01929 {
01930 return;
01931 }
01932
01933 if ( NPC->s.weapon == WP_SABER && g_spskill.integer >= 2 && NPCInfo->rank > RANK_LT_JG )
01934 {
01935 NPCInfo->nextBStateThink = level.time + FRAMETIME/2;
01936 }
01937 else
01938 {
01939 NPCInfo->nextBStateThink = level.time + FRAMETIME;
01940 }
01941
01942
01943 if (self->s.NPC_class != CLASS_VEHICLE ||
01944 !self->m_pVehicle)
01945 {
01946 NPC_ExecuteBState( self );
01947 }
01948
01949 #if AI_TIMERS
01950 int addTime = GetTime( startTime );
01951 if ( addTime > 50 )
01952 {
01953 Com_Printf( S_COLOR_RED"ERROR: NPC number %d, %s %s at %s, weaponnum: %d, using %d of AI time!!!\n", NPC->s.number, NPC->NPC_type, NPC->targetname, vtos(NPC->r.currentOrigin), NPC->s.weapon, addTime );
01954 }
01955 AITime += addTime;
01956 #endif// AI_TIMERS
01957 }
01958 else
01959 {
01960 VectorCopy( oldMoveDir, self->client->ps.moveDir );
01961
01962 NPCInfo->last_ucmd.serverTime = level.time - 50;
01963 if ( !NPC->next_roff_time || NPC->next_roff_time < level.time )
01964 {
01965
01966 NPC_UpdateAngles(qtrue, qtrue);
01967 memcpy( &ucmd, &NPCInfo->last_ucmd, sizeof( usercmd_t ) );
01968 ClientThink(NPC->s.number, &ucmd);
01969 }
01970 else
01971 {
01972 NPC_ApplyRoff();
01973 }
01974
01975 }
01976
01977 trap_ICARUS_MaintainTaskManager(self->s.number);
01978 VectorCopy(self->r.currentOrigin, self->client->ps.origin);
01979 }
01980
01981 void NPC_InitAI ( void )
01982 {
01983
01984
01985
01986
01987
01988
01989
01990
01991
01992
01993
01994
01995
01996
01997
01998
01999
02000
02001
02002
02003
02004
02005
02006
02007
02008
02009 }
02010
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029
02030
02031
02032
02033
02034
02035
02036
02037
02038
02039
02040
02041 void NPC_InitGame( void )
02042 {
02043
02044
02045
02046 NPC_LoadParms();
02047 NPC_InitAI();
02048
02049
02050
02051
02052
02053
02054
02055
02056 }
02057
02058 void NPC_SetAnim(gentity_t *ent, int setAnimParts, int anim, int setAnimFlags)
02059 {
02060
02061 G_SetAnim(ent, NULL, setAnimParts, anim, setAnimFlags, 0);
02062
02063
02064
02065
02066
02067
02068
02069
02070
02071
02072
02073
02074
02075
02076
02077
02078
02079
02080
02081
02082
02083
02084
02085
02086
02087
02088
02089
02090
02091
02092
02093
02094
02095
02096
02097
02098
02099
02100
02101
02102
02103
02104
02105
02106
02107
02108
02109
02110 }