00001
00002 #include "b_local.h"
00003 #include "anims.h"
00004 #include "w_saber.h"
00005
00006 extern qboolean G_CheckForStrongAttackMomentum( gentity_t *self );
00007 extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime );
00008 extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath );
00009 extern void cgi_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx );
00010 extern qboolean Q3_TaskIDPending( gentity_t *ent, taskID_t taskType );
00011 extern qboolean NPC_CheckLookTarget( gentity_t *self );
00012 extern void NPC_SetLookTarget( gentity_t *self, int entNum, int clearTime );
00013 extern qboolean Jedi_WaitingAmbush( gentity_t *self );
00014 extern void Jedi_Ambush( gentity_t *self );
00015 extern qboolean NPC_SomeoneLookingAtMe(gentity_t *ent);
00016
00017 #include "../namespace_begin.h"
00018 extern qboolean BG_SaberInSpecialAttack( int anim );
00019 extern qboolean PM_SpinningSaberAnim( int anim );
00020 extern qboolean PM_SpinningAnim( int anim );
00021 extern qboolean PM_InKnockDown( playerState_t *ps );
00022 extern qboolean BG_FlippingAnim( int anim );
00023 extern qboolean PM_RollingAnim( int anim );
00024 extern qboolean PM_InCartwheel( int anim );
00025 extern qboolean BG_CrouchAnim( int anim );
00026 #include "../namespace_end.h"
00027
00028 extern int teamLastEnemyTime[];
00029 extern int killPlayerTimer;
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 static void NPC_CheckAttacker( gentity_t *other, int mod )
00043 {
00044
00045
00046
00047
00048
00049 if ( !other )
00050 return;
00051
00052 if ( other == NPC )
00053 return;
00054
00055 if ( !other->inuse )
00056 return;
00057
00058
00059 if ( other->flags & FL_NOTARGET )
00060 return;
00061
00062
00063
00064
00065
00066
00067
00068
00069 if ( NPC->enemy == NULL )
00070 {
00071 G_SetEnemy( NPC, other );
00072 return;
00073 }
00074
00075
00076 if ( NPC->enemy->health <= 0 )
00077 {
00078 G_ClearEnemy( NPC );
00079 G_SetEnemy( NPC, other );
00080 return;
00081 }
00082
00083
00084 if ( other == NPC->enemy )
00085 return;
00086
00087 if ( NPC->client->ps.weapon == WP_SABER )
00088 {
00089 if ( mod == MOD_SABER )
00090 {
00091
00092 G_ClearEnemy( NPC );
00093 G_SetEnemy( NPC, other );
00094 return;
00095 }
00096 }
00097
00098 if ( other == &g_entities[0] )
00099 {
00100
00101 float luckThreshold;
00102
00103 switch ( g_spskill.integer )
00104 {
00105
00106 case 0:
00107 luckThreshold = 0.9f;
00108 break;
00109
00110
00111 case 1:
00112 luckThreshold = 0.5f;
00113 break;
00114
00115
00116 case 2:
00117 default:
00118 luckThreshold = 0.0f;
00119 break;
00120 }
00121
00122
00123 if ( random() > luckThreshold )
00124 {
00125 G_ClearEnemy( other );
00126 other->enemy = NPC;
00127 }
00128
00129 return;
00130 }
00131 }
00132
00133 void NPC_SetPainEvent( gentity_t *self )
00134 {
00135 if ( !self->NPC || !(self->NPC->aiFlags&NPCAI_DIE_ON_IMPACT) )
00136 {
00137
00138
00139
00140
00141 if (!trap_ICARUS_TaskIDPending(self, TID_CHAN_VOICE) && self->client)
00142 {
00143
00144 G_AddEvent( self, EV_PAIN, floor((float)self->health/self->client->ps.stats[STAT_MAX_HEALTH]*100.0f) );
00145
00146 }
00147
00148 }
00149 }
00150
00151
00152
00153
00154
00155
00156
00157 float NPC_GetPainChance( gentity_t *self, int damage )
00158 {
00159 float pain_chance;
00160 if ( !self->enemy )
00161 {
00162 return 1.0f;
00163 }
00164
00165 if (!self->client)
00166 {
00167 return 1.0f;
00168 }
00169
00170
00171 if (damage > self->client->ps.stats[STAT_MAX_HEALTH]/2.0f)
00172 {
00173 return 1.0f;
00174 }
00175
00176 pain_chance = (float)(self->client->ps.stats[STAT_MAX_HEALTH]-self->health)/(self->client->ps.stats[STAT_MAX_HEALTH]*2.0f) + (float)damage/(self->client->ps.stats[STAT_MAX_HEALTH]/2.0f);
00177 switch ( g_spskill.integer )
00178 {
00179 case 0:
00180
00181 break;
00182
00183 case 1:
00184 pain_chance *= 0.5f;
00185
00186 break;
00187
00188 case 2:
00189 default:
00190 pain_chance *= 0.1f;
00191
00192 break;
00193 }
00194
00195 return pain_chance;
00196 }
00197
00198
00199
00200
00201
00202
00203
00204 #define MIN_PAIN_TIME 200
00205
00206 extern int G_PickPainAnim( gentity_t *self, vec3_t point, int damage, int hitLoc );
00207 void NPC_ChoosePainAnimation( gentity_t *self, gentity_t *other, vec3_t point, int damage, int mod, int hitLoc, int voiceEvent )
00208 {
00209 int pain_anim = -1;
00210 float pain_chance;
00211
00212
00213 if ( level.time < self->painDebounceTime && mod != MOD_MELEE )
00214 {
00215 return;
00216 }
00217
00218 if ( self->s.weapon == WP_THERMAL && self->client->ps.weaponTime > 0 )
00219 {
00220 return;
00221 }
00222 else if ( self->client->NPC_class == CLASS_GALAKMECH )
00223 {
00224 if ( hitLoc == HL_GENERIC1 )
00225 {
00226 pain_chance = 1.0f;
00227
00228
00229
00230 }
00231
00232
00233
00234
00235
00236 else if ( self->health > 200 && damage < 100 )
00237 {
00238 pain_chance = 0.05f;
00239 }
00240 else
00241 {
00242 pain_chance = (200.0f-self->health)/100.0f + damage/50.0f;
00243 }
00244 }
00245 else if ( self->client && self->client->playerTeam == NPCTEAM_PLAYER && other && !other->s.number )
00246 {
00247 pain_chance = 1.1f;
00248 }
00249 else
00250 {
00251 if ( other && other->s.weapon == WP_SABER || mod == MOD_CRUSH )
00252 {
00253 pain_chance = 1.0f;
00254 }
00255 else if ( mod == MOD_MELEE )
00256 {
00257 pain_chance = 1.0f - ((RANK_CAPTAIN-self->NPC->rank)/(float)RANK_CAPTAIN);
00258 }
00259 else if ( self->client->NPC_class == CLASS_PROTOCOL )
00260 {
00261 pain_chance = 1.0f;
00262 }
00263 else
00264 {
00265 pain_chance = NPC_GetPainChance( self, damage );
00266 }
00267 if ( self->client->NPC_class == CLASS_DESANN )
00268 {
00269 pain_chance *= 0.5f;
00270 }
00271 }
00272
00273
00274 if ( random() < pain_chance )
00275 {
00276 int animLength;
00277
00278
00279 if ( self->client->ps.fd.forceGripBeingGripped < level.time )
00280 {
00281 if (
00282 PM_SpinningAnim( self->client->ps.legsAnim )
00283 || BG_SaberInSpecialAttack( self->client->ps.torsoAnim )
00284 || PM_InKnockDown( &self->client->ps )
00285 || PM_RollingAnim( self->client->ps.legsAnim )
00286 || (BG_FlippingAnim( self->client->ps.legsAnim )&&!PM_InCartwheel( self->client->ps.legsAnim )) )
00287 {
00288 }
00289 else
00290 {
00291 int parts;
00292
00293 if ( self->client->NPC_class == CLASS_GALAKMECH )
00294 {
00295
00296 pain_anim = BOTH_PAIN1;
00297 }
00298 else if ( mod == MOD_MELEE )
00299 {
00300 pain_anim = BG_PickAnim( self->localAnimIndex, BOTH_PAIN2, BOTH_PAIN3 );
00301 }
00302 else if ( self->s.weapon == WP_SABER )
00303 {
00304 pain_anim = BG_PickAnim( self->localAnimIndex, BOTH_PAIN2, BOTH_PAIN3 );
00305 }
00306
00307
00308
00309
00310
00311
00312
00313 if ( pain_anim == -1 )
00314 {
00315 pain_anim = BG_PickAnim( self->localAnimIndex, BOTH_PAIN1, BOTH_PAIN18 );
00316 }
00317 self->client->ps.fd.saberAnimLevel = FORCE_LEVEL_1;
00318 self->client->ps.saberMove = LS_READY;
00319 parts = SETANIM_BOTH;
00320 if ( BG_CrouchAnim( self->client->ps.legsAnim ) || PM_InCartwheel( self->client->ps.legsAnim ) )
00321 {
00322 parts = SETANIM_LEGS;
00323 }
00324
00325 if (pain_anim != -1)
00326 {
00327 NPC_SetAnim( self, parts, pain_anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
00328 }
00329 }
00330 if ( voiceEvent != -1 )
00331 {
00332 G_AddVoiceEvent( self, voiceEvent, Q_irand( 2000, 4000 ) );
00333 }
00334 else
00335 {
00336 NPC_SetPainEvent( self );
00337 }
00338 }
00339 else
00340 {
00341 G_AddVoiceEvent( self, Q_irand(EV_CHOKE1, EV_CHOKE3), 0 );
00342 }
00343
00344
00345
00346
00347
00348
00349
00350
00351 animLength = bgAllAnims[self->localAnimIndex].anims[pain_anim].numFrames * fabs((float)(bgHumanoidAnimations[pain_anim].frameLerp));
00352
00353 self->painDebounceTime = level.time + animLength;
00354 self->client->ps.weaponTime = 0;
00355 }
00356 }
00357
00358
00359
00360
00361
00362
00363 void NPC_Pain(gentity_t *self, gentity_t *attacker, int damage)
00364 {
00365 team_t otherTeam = TEAM_FREE;
00366 int voiceEvent = -1;
00367 gentity_t *other = attacker;
00368 int mod = gPainMOD;
00369 int hitLoc = gPainHitLoc;
00370 vec3_t point;
00371
00372 VectorCopy(gPainPoint, point);
00373
00374 if ( self->NPC == NULL )
00375 return;
00376
00377 if ( other == NULL )
00378 return;
00379
00380
00381 if ( self->client->ps.pm_type == PM_DEAD )
00382 return;
00383
00384 if ( other == self )
00385 return;
00386
00387
00388 if ( other->client )
00389 {
00390 otherTeam = other->client->playerTeam;
00391
00392
00393
00394
00395 }
00396
00397 if ( self->client->playerTeam
00398 && other->client
00399 && otherTeam == self->client->playerTeam
00400 )
00401
00402 {
00403 if ( other != self->enemy && self != other->enemy )
00404 {
00405 if ( self->enemy || other->enemy
00406
00407
00408
00409
00410 )
00411 {
00412
00413
00414 if ( self->client && self->NPC )
00415 {
00416 if ( self->health <= (self->client->ps.stats[STAT_MAX_HEALTH]/3) && G_ActivateBehavior(self, BSET_FLEE) )
00417 {
00418
00419 }
00420 else
00421 {
00422 G_ActivateBehavior(self, BSET_PAIN);
00423 }
00424 }
00425 if ( damage != -1 )
00426 {
00427
00428 if ( Q_irand( 0, 1 ) )
00429 {
00430 NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, EV_FFWARN );
00431 }
00432 else
00433 {
00434 NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, -1 );
00435 }
00436 }
00437 return;
00438 }
00439 else if ( self->NPC && !other->s.number )
00440 {
00441 if ( self->NPC->charmedTime )
00442 {
00443 return;
00444 }
00445 else if ( self->NPC->ffireCount < 3+((2-g_spskill.integer)*2) )
00446 {
00447
00448 if ( damage != -1 )
00449 {
00450
00451 if ( Q_irand( 0, 1 ) )
00452 {
00453 NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, EV_FFWARN );
00454 }
00455 else
00456 {
00457 NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, -1 );
00458 }
00459 }
00460 return;
00461 }
00462 else if ( G_ActivateBehavior( self, BSET_FFIRE ) )
00463 {
00464 return;
00465 }
00466 else
00467 {
00468 self->NPC->blockedSpeechDebounceTime = 0;
00469 voiceEvent = EV_FFTURN;
00470 self->NPC->behaviorState = self->NPC->tempBehavior = self->NPC->defaultBehavior = BS_DEFAULT;
00471 other->flags &= ~FL_NOTARGET;
00472
00473 self->r.svFlags &= ~SVF_ICARUS_FREEZE;
00474 G_SetEnemy( self, other );
00475
00476 self->NPC->scriptFlags &= ~(SCF_DONT_FIRE|SCF_CROUCHED|SCF_WALKING|SCF_NO_COMBAT_TALK|SCF_FORCED_MARCH);
00477 self->NPC->scriptFlags |= (SCF_CHASE_ENEMIES|SCF_NO_MIND_TRICK);
00478
00479
00480
00481 if ( !killPlayerTimer )
00482 {
00483 killPlayerTimer = level.time + 10000;
00484 }
00485 }
00486 }
00487 }
00488 }
00489
00490 SaveNPCGlobals();
00491 SetNPCGlobals( self );
00492
00493
00494 if ( NPCInfo->ignorePain == qfalse )
00495 {
00496 NPCInfo->confusionTime = 0;
00497 if ( damage != -1 )
00498 {
00499
00500 NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, voiceEvent );
00501 }
00502
00503 if ( NPC->enemy != other && NPC != other )
00504 {
00505 NPC_CheckAttacker( other, mod );
00506 }
00507 }
00508
00509
00510 if ( self->client && self->NPC )
00511 {
00512
00513 if(self->health <= (self->client->ps.stats[STAT_MAX_HEALTH]/3) && G_ActivateBehavior(self, BSET_FLEE) )
00514 {
00515 }
00516 else
00517 {
00518 G_ActivateBehavior(self, BSET_PAIN);
00519 }
00520 }
00521
00522
00523 if( self->paintarget && self->paintarget[0] )
00524 {
00525 G_UseTargets2(self, other, self->paintarget);
00526 }
00527
00528 RestoreNPCGlobals();
00529 }
00530
00531
00532
00533
00534
00535
00536 extern qboolean INV_SecurityKeyGive( gentity_t *target, const char *keyname );
00537 void NPC_Touch(gentity_t *self, gentity_t *other, trace_t *trace)
00538 {
00539 if(!self->NPC)
00540 return;
00541
00542 SaveNPCGlobals();
00543 SetNPCGlobals( self );
00544
00545 if ( self->message && self->health <= 0 )
00546 {
00547
00548 if (other && other->client && other->s.number < MAX_CLIENTS)
00549 {
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592 }
00593 }
00594
00595 if ( other->client )
00596 {
00597
00598 if ( other->health > 0 )
00599 {
00600 NPCInfo->touchedByPlayer = other;
00601 }
00602
00603 if ( other == NPCInfo->goalEntity )
00604 {
00605 NPCInfo->aiFlags |= NPCAI_TOUCHED_GOAL;
00606 }
00607
00608 if( !(other->flags & FL_NOTARGET) )
00609 {
00610 if ( self->client->enemyTeam )
00611 {
00612 if ( other->client->playerTeam == self->client->enemyTeam )
00613 {
00614 if( NPCInfo->behaviorState != BS_HUNT_AND_KILL && !NPCInfo->tempBehavior )
00615 {
00616
00617 if ( NPC->enemy != other )
00618 {
00619 G_SetEnemy( NPC, other );
00620 }
00621
00622 }
00623 }
00624 }
00625 }
00626
00627
00628
00629
00630
00631
00632
00633
00634 }
00635 else
00636 {
00637 if ( other->health > 0 )
00638 {
00639
00640 if (0)
00641 {
00642 NPCInfo->touchedByPlayer = other;
00643 }
00644 }
00645
00646 if ( other == NPCInfo->goalEntity )
00647 {
00648 NPCInfo->aiFlags |= NPCAI_TOUCHED_GOAL;
00649 }
00650 }
00651
00652 RestoreNPCGlobals();
00653 }
00654
00655
00656
00657
00658
00659
00660
00661 void NPC_TempLookTarget( gentity_t *self, int lookEntNum, int minLookTime, int maxLookTime )
00662 {
00663 if ( !self->client )
00664 {
00665 return;
00666 }
00667
00668 if ( (self->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
00669 {
00670 return;
00671 }
00672
00673 if ( !minLookTime )
00674 {
00675 minLookTime = 1000;
00676 }
00677
00678 if ( !maxLookTime )
00679 {
00680 maxLookTime = 1000;
00681 }
00682
00683 if ( !NPC_CheckLookTarget( self ) )
00684 {
00685
00686 NPC_SetLookTarget( self, lookEntNum, level.time + Q_irand( minLookTime, maxLookTime ) );
00687 }
00688 }
00689
00690 void NPC_Respond( gentity_t *self, int userNum )
00691 {
00692 int event = -1;
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705 if ( !Q_irand( 0, 1 ) )
00706 {
00707 NPC_TempLookTarget( self, userNum, 1000, 3000 );
00708 }
00709
00710
00711 switch ( self->client->NPC_class )
00712 {
00713 case CLASS_JAN:
00714 if ( self->enemy )
00715 {
00716 if ( !Q_irand( 0, 2 ) )
00717 {
00718 event = Q_irand( EV_CHASE1, EV_CHASE3 );
00719 }
00720 else if ( Q_irand( 0, 1 ) )
00721 {
00722 event = Q_irand( EV_OUTFLANK1, EV_OUTFLANK2 );
00723 }
00724 else
00725 {
00726 event = Q_irand( EV_COVER1, EV_COVER5 );
00727 }
00728 }
00729 else if ( !Q_irand( 0, 2 ) )
00730 {
00731 event = EV_SUSPICIOUS4;
00732 }
00733 else if ( !Q_irand( 0, 1 ) )
00734 {
00735 event = EV_SOUND1;
00736 }
00737 else
00738 {
00739 event = EV_CONFUSE1;
00740 }
00741 break;
00742 case CLASS_LANDO:
00743 if ( self->enemy )
00744 {
00745 if ( !Q_irand( 0, 2 ) )
00746 {
00747 event = Q_irand( EV_CHASE1, EV_CHASE3 );
00748 }
00749 else if ( Q_irand( 0, 1 ) )
00750 {
00751 event = Q_irand( EV_OUTFLANK1, EV_OUTFLANK2 );
00752 }
00753 else
00754 {
00755 event = Q_irand( EV_COVER1, EV_COVER5 );
00756 }
00757 }
00758 else if ( !Q_irand( 0, 6 ) )
00759 {
00760 event = EV_SIGHT2;
00761 }
00762 else if ( !Q_irand( 0, 5 ) )
00763 {
00764 event = EV_GIVEUP4;
00765 }
00766 else if ( Q_irand( 0, 4 ) > 1 )
00767 {
00768 event = Q_irand( EV_SOUND1, EV_SOUND3 );
00769 }
00770 else
00771 {
00772 event = Q_irand( EV_JDETECTED1, EV_JDETECTED2 );
00773 }
00774 break;
00775 case CLASS_LUKE:
00776 if ( self->enemy )
00777 {
00778 event = EV_COVER1;
00779 }
00780 else
00781 {
00782 event = Q_irand( EV_SOUND1, EV_SOUND3 );
00783 }
00784 break;
00785 case CLASS_JEDI:
00786 if ( !self->enemy )
00787 {
00788
00789
00790
00791
00792
00793 if (0)
00794 {
00795 event = Q_irand( EV_ANGER1, EV_ANGER3 );
00796 }
00797 else
00798 {
00799 event = Q_irand( EV_TAUNT1, EV_TAUNT2 );
00800 }
00801 }
00802 break;
00803 case CLASS_PRISONER:
00804 if ( self->enemy )
00805 {
00806 if ( Q_irand( 0, 1 ) )
00807 {
00808 event = Q_irand( EV_CHASE1, EV_CHASE3 );
00809 }
00810 else
00811 {
00812 event = Q_irand( EV_OUTFLANK1, EV_OUTFLANK2 );
00813 }
00814 }
00815 else
00816 {
00817 event = Q_irand( EV_SOUND1, EV_SOUND3 );
00818 }
00819 break;
00820 case CLASS_REBEL:
00821 if ( self->enemy )
00822 {
00823 if ( !Q_irand( 0, 2 ) )
00824 {
00825 event = Q_irand( EV_CHASE1, EV_CHASE3 );
00826 }
00827 else
00828 {
00829 event = Q_irand( EV_DETECTED1, EV_DETECTED5 );
00830 }
00831 }
00832 else
00833 {
00834 event = Q_irand( EV_SOUND1, EV_SOUND3 );
00835 }
00836 break;
00837 case CLASS_BESPIN_COP:
00838 if ( !Q_stricmp( "bespincop", self->NPC_type ) )
00839 {
00840 if ( self->enemy )
00841 {
00842 if ( Q_irand( 0, 9 ) > 6 )
00843 {
00844 event = Q_irand( EV_CHASE1, EV_CHASE3 );
00845 }
00846 else if ( Q_irand( 0, 6 ) > 4 )
00847 {
00848 event = Q_irand( EV_OUTFLANK1, EV_OUTFLANK2 );
00849 }
00850 else
00851 {
00852 event = Q_irand( EV_COVER1, EV_COVER5 );
00853 }
00854 }
00855 else if ( !Q_irand( 0, 3 ) )
00856 {
00857 event = Q_irand( EV_SIGHT2, EV_SIGHT3 );
00858 }
00859 else if ( !Q_irand( 0, 1 ) )
00860 {
00861 event = Q_irand( EV_SOUND1, EV_SOUND3 );
00862 }
00863 else if ( !Q_irand( 0, 2 ) )
00864 {
00865 event = EV_LOST1;
00866 }
00867 else if ( !Q_irand( 0, 1 ) )
00868 {
00869 event = EV_ESCAPING2;
00870 }
00871 else
00872 {
00873 event = EV_GIVEUP4;
00874 }
00875 }
00876 else
00877 {
00878 if ( self->enemy )
00879 {
00880 if ( Q_irand( 0, 9 ) > 6 )
00881 {
00882 event = Q_irand( EV_CHASE1, EV_CHASE3 );
00883 }
00884 else if ( Q_irand( 0, 6 ) > 4 )
00885 {
00886 event = Q_irand( EV_OUTFLANK1, EV_OUTFLANK2 );
00887 }
00888 else
00889 {
00890 event = Q_irand( EV_COVER1, EV_COVER5 );
00891 }
00892 }
00893 else if ( !Q_irand( 0, 3 ) )
00894 {
00895 event = Q_irand( EV_SIGHT1, EV_SIGHT2 );
00896 }
00897 else if ( !Q_irand( 0, 1 ) )
00898 {
00899 event = Q_irand( EV_SOUND1, EV_SOUND3 );
00900 }
00901 else if ( !Q_irand( 0, 2 ) )
00902 {
00903 event = EV_LOST1;
00904 }
00905 else if ( !Q_irand( 0, 1 ) )
00906 {
00907 event = EV_GIVEUP3;
00908 }
00909 else
00910 {
00911 event = EV_CONFUSE1;
00912 }
00913 }
00914 break;
00915 case CLASS_R2D2:
00916 G_Sound(self, CHAN_AUTO, G_SoundIndex(va("sound/chars/r2d2/misc/r2d2talk0%d.wav",Q_irand(1, 3))));
00917 break;
00918 case CLASS_R5D2:
00919 G_Sound(self, CHAN_AUTO, G_SoundIndex(va("sound/chars/r5d2/misc/r5talk%d.wav",Q_irand(1, 4))));
00920 break;
00921 case CLASS_MOUSE:
00922 G_Sound(self, CHAN_AUTO, G_SoundIndex(va("sound/chars/mouse/misc/mousego%d.wav",Q_irand(1, 3))));
00923 break;
00924 case CLASS_GONK:
00925 G_Sound(self, CHAN_AUTO, G_SoundIndex(va("sound/chars/gonk/misc/gonktalk%d.wav",Q_irand(1, 2))));
00926 break;
00927 }
00928
00929 if ( event != -1 )
00930 {
00931
00932 qboolean addFlag = (self->NPC->scriptFlags&SCF_NO_COMBAT_TALK);
00933 self->NPC->scriptFlags &= ~SCF_NO_COMBAT_TALK;
00934
00935 G_AddVoiceEvent( self, event, 3000 );
00936
00937 if ( addFlag )
00938 {
00939 self->NPC->scriptFlags |= SCF_NO_COMBAT_TALK;
00940 }
00941 }
00942 }
00943
00944
00945
00946
00947
00948
00949
00950 void NPC_UseResponse( gentity_t *self, gentity_t *user, qboolean useWhenDone )
00951 {
00952 if ( !self->NPC || !self->client )
00953 {
00954 return;
00955 }
00956
00957 if ( user->s.number != 0 )
00958 {
00959 if ( useWhenDone )
00960 {
00961 G_ActivateBehavior( self, BSET_USE );
00962 }
00963 return;
00964 }
00965
00966 if ( user->client && self->client->playerTeam != user->client->playerTeam && self->client->playerTeam != NPCTEAM_NEUTRAL )
00967 {
00968 if ( useWhenDone )
00969 {
00970 G_ActivateBehavior( self, BSET_USE );
00971 }
00972 return;
00973 }
00974
00975 if ( self->NPC->blockedSpeechDebounceTime > level.time )
00976 {
00977 return;
00978 }
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991 if ( useWhenDone )
00992 {
00993 G_ActivateBehavior( self, BSET_USE );
00994 }
00995 else
00996 {
00997 NPC_Respond( self, user->s.number );
00998 }
00999 }
01000
01001
01002
01003
01004
01005
01006 extern void Add_Batteries( gentity_t *ent, int *count );
01007
01008 void NPC_Use( gentity_t *self, gentity_t *other, gentity_t *activator )
01009 {
01010 if (self->client->ps.pm_type == PM_DEAD)
01011 {
01012 return;
01013 }
01014
01015 SaveNPCGlobals();
01016 SetNPCGlobals( self );
01017
01018 if(self->client && self->NPC)
01019 {
01020
01021 if ( self->client->NPC_class == CLASS_VEHICLE )
01022 {
01023 Vehicle_t *pVeh = self->m_pVehicle;
01024
01025 if ( pVeh && pVeh->m_pVehicleInfo )
01026 {
01027
01028 if ( other == self )
01029 {
01030 pVeh->m_pVehicleInfo->EjectAll( pVeh );
01031 }
01032
01033 else if ( other->s.owner == self->s.number )
01034 {
01035 pVeh->m_pVehicleInfo->Eject( pVeh, (bgEntity_t *)other, qfalse );
01036 }
01037
01038 else
01039 {
01040 pVeh->m_pVehicleInfo->Board( pVeh, (bgEntity_t *)other );
01041 }
01042 }
01043 }
01044 else if ( Jedi_WaitingAmbush( NPC ) )
01045 {
01046 Jedi_Ambush( NPC );
01047 }
01048
01049 if ( activator && activator->s.number == 0 && self->client->NPC_class == CLASS_GONK )
01050 {
01051
01052
01053
01054
01055 }
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075 if ( self->behaviorSet[BSET_USE] )
01076 {
01077 NPC_UseResponse( self, other, qtrue );
01078 }
01079
01080
01081
01082
01083 else if ( !self->enemy
01084 && activator->s.number == 0
01085 && !(self->NPC->scriptFlags&SCF_NO_RESPONSE) )
01086
01087 {
01088 NPC_UseResponse( self, other, qfalse );
01089 }
01090 }
01091
01092 RestoreNPCGlobals();
01093 }
01094
01095 void NPC_CheckPlayerAim( void )
01096 {
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111 }
01112
01113 void NPC_CheckAllClear( void )
01114 {
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125 }