00001
00002
00003 #include "b_local.h"
00004 #include "anims.h"
00005 #include "w_saber.h"
00006 #include "bg_saga.h"
00007 #include "bg_vehicles.h"
00008 #include "g_nav.h"
00009
00010 extern void G_DebugPrint( int level, const char *format, ... );
00011
00012 extern qboolean G_CheckInSolid (gentity_t *self, qboolean fix);
00013 extern void ClientUserinfoChanged( int clientNum );
00014 extern qboolean SpotWouldTelefrag2( gentity_t *mover, vec3_t dest );
00015 extern void Jedi_Cloak( gentity_t *self );
00016
00017
00018
00019 extern void Q3_SetParm (int entID, int parmNum, const char *parmValue);
00020 extern team_t TranslateTeamName( const char *name );
00021 extern char *TeamNames[TEAM_NUM_TEAMS];
00022
00023
00024
00025
00026
00027 extern void PM_SetTorsoAnimTimer( gentity_t *ent, int *torsoAnimTimer, int time );
00028 extern void PM_SetLegsAnimTimer( gentity_t *ent, int *legsAnimTimer, int time );
00029
00030 extern void ST_ClearTimers( gentity_t *ent );
00031 extern void Jedi_ClearTimers( gentity_t *ent );
00032 extern void NPC_ShadowTrooper_Precache( void );
00033 extern void NPC_Gonk_Precache( void );
00034 extern void NPC_Mouse_Precache( void );
00035 extern void NPC_Seeker_Precache( void );
00036 extern void NPC_Remote_Precache( void );
00037 extern void NPC_R2D2_Precache(void);
00038 extern void NPC_R5D2_Precache(void);
00039 extern void NPC_Probe_Precache(void);
00040 extern void NPC_Interrogator_Precache(gentity_t *self);
00041 extern void NPC_MineMonster_Precache( void );
00042 extern void NPC_Howler_Precache( void );
00043 extern void NPC_ATST_Precache(void);
00044 extern void NPC_Sentry_Precache(void);
00045 extern void NPC_Mark1_Precache(void);
00046 extern void NPC_Mark2_Precache(void);
00047 extern void NPC_GalakMech_Precache( void );
00048 extern void NPC_GalakMech_Init( gentity_t *ent );
00049 extern void NPC_Protocol_Precache( void );
00050 extern void Boba_Precache( void );
00051 extern void NPC_Wampa_Precache( void );
00052 gentity_t *NPC_SpawnType( gentity_t *ent, char *npc_type, char *targetname, qboolean isVehicle );
00053
00054 extern void Rancor_SetBolts( gentity_t *self );
00055 extern void Wampa_SetBolts( gentity_t *self );
00056
00057 #define NSF_DROP_TO_FLOOR 16
00058
00059
00060
00061 extern void funcBBrushPain (gentity_t *self, gentity_t *attacker, int damage);
00062 extern void misc_model_breakable_pain (gentity_t *self, gentity_t *attacker, int damage);
00063 extern void NPC_Pain (gentity_t *self, gentity_t *attacker, int damage);
00064 extern void station_pain (gentity_t *self, gentity_t *attacker, int damage);
00065 extern void func_usable_pain (gentity_t *self, gentity_t *attacker, int damage);
00066 extern void NPC_ATST_Pain (gentity_t *self, gentity_t *attacker, int damage);
00067 extern void NPC_ST_Pain (gentity_t *self, gentity_t *attacker, int damage);
00068 extern void NPC_Jedi_Pain (gentity_t *self, gentity_t *attacker, int damage);
00069 extern void NPC_Droid_Pain (gentity_t *self, gentity_t *attacker, int damage);
00070 extern void NPC_Probe_Pain (gentity_t *self, gentity_t *attacker, int damage);
00071 extern void NPC_MineMonster_Pain (gentity_t *self, gentity_t *attacker, int damage);
00072 extern void NPC_Howler_Pain (gentity_t *self, gentity_t *attacker, int damage);
00073 extern void NPC_Seeker_Pain (gentity_t *self, gentity_t *attacker, int damage);
00074 extern void NPC_Remote_Pain (gentity_t *self, gentity_t *attacker, int damage);
00075 extern void emplaced_gun_pain (gentity_t *self, gentity_t *attacker, int damage);
00076 extern void NPC_Mark1_Pain (gentity_t *self, gentity_t *attacker, int damage);
00077 extern void NPC_GM_Pain (gentity_t *self, gentity_t *attacker, int damage);
00078 extern void NPC_Sentry_Pain (gentity_t *self, gentity_t *attacker, int damage);
00079 extern void NPC_Mark2_Pain (gentity_t *self, gentity_t *attacker, int damage);
00080 extern void PlayerPain (gentity_t *self, gentity_t *attacker, int damage);
00081 extern void GasBurst (gentity_t *self, gentity_t *attacker, int damage);
00082 extern void CrystalCratePain (gentity_t *self, gentity_t *attacker, int damage);
00083 extern void TurretPain (gentity_t *self, gentity_t *attacker, int damage);
00084 extern void NPC_Wampa_Pain (gentity_t *self, gentity_t *attacker, int damage);
00085 extern void NPC_Rancor_Pain (gentity_t *self, gentity_t *attacker, int damage);
00086
00087
00088
00089
00090 int WP_SetSaberModel( gclient_t *client, class_t npcClass )
00091 {
00092
00093 return 1;
00094 }
00095
00096
00097
00098
00099
00100
00101 typedef void (PAIN_FUNC) (gentity_t *self, gentity_t *attacker, int damage);
00102
00103 PAIN_FUNC *NPC_PainFunc( gentity_t *ent )
00104 {
00105 void (*func)(gentity_t *self, gentity_t *attacker, int damage);
00106
00107 if ( ent->client->ps.weapon == WP_SABER )
00108 {
00109 func = NPC_Jedi_Pain;
00110 }
00111 else
00112 {
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122 switch( ent->client->NPC_class )
00123 {
00124
00125 case CLASS_STORMTROOPER:
00126 case CLASS_SWAMPTROOPER:
00127 func = NPC_ST_Pain;
00128 break;
00129
00130 case CLASS_SEEKER:
00131 func = NPC_Seeker_Pain;
00132 break;
00133
00134 case CLASS_REMOTE:
00135 func = NPC_Remote_Pain;
00136 break;
00137
00138 case CLASS_MINEMONSTER:
00139 func = NPC_MineMonster_Pain;
00140 break;
00141
00142 case CLASS_HOWLER:
00143 func = NPC_Howler_Pain;
00144 break;
00145
00146
00147 case CLASS_GONK:
00148 case CLASS_R2D2:
00149 case CLASS_R5D2:
00150 case CLASS_MOUSE:
00151 case CLASS_PROTOCOL:
00152 case CLASS_INTERROGATOR:
00153 func = NPC_Droid_Pain;
00154 break;
00155 case CLASS_PROBE:
00156 func = NPC_Probe_Pain;
00157 break;
00158
00159 case CLASS_SENTRY:
00160 func = NPC_Sentry_Pain;
00161 break;
00162 case CLASS_MARK1:
00163 func = NPC_Mark1_Pain;
00164 break;
00165 case CLASS_MARK2:
00166 func = NPC_Mark2_Pain;
00167 break;
00168 case CLASS_ATST:
00169 func = NPC_ATST_Pain;
00170 break;
00171 case CLASS_GALAKMECH:
00172 func = NPC_GM_Pain;
00173 break;
00174 case CLASS_RANCOR:
00175 func = NPC_Rancor_Pain;
00176 break;
00177 case CLASS_WAMPA:
00178 func = NPC_Wampa_Pain;
00179 break;
00180
00181 default:
00182 func = NPC_Pain;
00183 break;
00184 }
00185
00186 }
00187
00188 return func;
00189 }
00190
00191
00192
00193
00194
00195
00196
00197 typedef void (TOUCH_FUNC) (gentity_t *self, gentity_t *other, trace_t *trace);
00198
00199 TOUCH_FUNC *NPC_TouchFunc( gentity_t *ent )
00200 {
00201 void (*func)(gentity_t *self, gentity_t *other, trace_t *trace);
00202
00203 func = NPC_Touch;
00204
00205 return func;
00206 }
00207
00208
00209
00210
00211
00212
00213
00214 extern void G_CreateG2AttachedWeaponModel( gentity_t *ent, const char *weaponModel, int boltNum, int weaponNum );
00215 void NPC_SetMiscDefaultData( gentity_t *ent )
00216 {
00217 if ( ent->spawnflags & SFB_CINEMATIC )
00218 {
00219 ent->NPC->behaviorState = BS_CINEMATIC;
00220 }
00221 if ( ent->client->NPC_class == CLASS_BOBAFETT )
00222 {
00223 Boba_Precache();
00224 ent->client->ps.fd.forcePowersKnown |= ( 1 << FP_LEVITATION );
00225 ent->client->ps.fd.forcePowerLevel[FP_LEVITATION] = FORCE_LEVEL_3;
00226 ent->client->ps.fd.forcePower = 100;
00227 ent->NPC->scriptFlags |= (SCF_ALT_FIRE|SCF_NO_GROUPS);
00228 }
00229
00230 if (ent->s.NPC_class == CLASS_VEHICLE && ent->m_pVehicle)
00231 {
00232 ent->s.g2radius = 255;
00233
00234 if (ent->m_pVehicle->m_pVehicleInfo->type == VH_WALKER)
00235 {
00236 ent->mass = 2000;
00237 ent->flags |= (FL_SHIELDED|FL_NO_KNOCKBACK);
00238 ent->pain = NPC_ATST_Pain;
00239 }
00240
00241 trap_G2API_SetSurfaceOnOff( ent->ghoul2, "head_hatchcover", 0 );
00242 }
00243 if ( !Q_stricmp( "wampa", ent->NPC_type ) )
00244 {
00245 Wampa_SetBolts( ent );
00246 ent->s.g2radius = 80;
00247 ent->mass = 300;
00248 ent->flags |= FL_NO_KNOCKBACK;
00249 ent->pain = NPC_Wampa_Pain;
00250 }
00251 if ( ent->client->NPC_class == CLASS_RANCOR )
00252 {
00253 Rancor_SetBolts( ent );
00254 ent->s.g2radius = 255;
00255 ent->mass = 1000;
00256 ent->flags |= FL_NO_KNOCKBACK;
00257 ent->pain = NPC_Rancor_Pain;
00258 ent->health *= 4;
00259 }
00260 if ( !Q_stricmp( "Yoda", ent->NPC_type ) )
00261 {
00262 ent->NPC->scriptFlags |= SCF_NO_FORCE;
00263 }
00264 if ( !Q_stricmp( "emperor", ent->NPC_type ) )
00265 {
00266 ent->NPC->scriptFlags |= SCF_DONT_FIRE;
00267 }
00268
00269
00270 if (ent->client->ps.weapon == WP_SABER)
00271 {
00272
00273
00274 WP_SaberInitBladeData( ent );
00275 ent->client->ps.saberHolstered = 2;
00276
00277
00278
00279
00280
00281 Jedi_ClearTimers( ent );
00282 }
00283 if ( ent->client->ps.fd.forcePowersKnown != 0 )
00284 {
00285 WP_InitForcePowers( ent );
00286 WP_SpawnInitForcePowers(ent);
00287 }
00288 if ( ent->client->NPC_class == CLASS_SEEKER )
00289 {
00290 ent->NPC->defaultBehavior = BS_DEFAULT;
00291 ent->client->ps.gravity = 0;
00292 ent->NPC->aiFlags |= NPCAI_CUSTOM_GRAVITY;
00293 ent->client->ps.eFlags2 |= EF2_FLYING;
00294 ent->count = 30;
00295 }
00296
00297 switch(ent->client->playerTeam)
00298 {
00299 case NPCTEAM_PLAYER:
00300
00301 if ( ent->client->NPC_class == CLASS_JEDI || ent->client->NPC_class == CLASS_LUKE )
00302 {
00303 ent->client->enemyTeam = NPCTEAM_ENEMY;
00304 if ( ent->spawnflags & JSF_AMBUSH )
00305 {
00306 ent->NPC->scriptFlags |= SCF_IGNORE_ALERTS;
00307 ent->client->noclip = qtrue;
00308 }
00309 }
00310 else
00311 {
00312
00313
00314
00315
00316
00317
00318 switch ( ent->client->ps.weapon )
00319 {
00320 case WP_BRYAR_PISTOL:
00321
00322 case WP_DISRUPTOR:
00323 case WP_BOWCASTER:
00324 case WP_REPEATER:
00325 case WP_DEMP2:
00326 case WP_FLECHETTE:
00327 case WP_ROCKET_LAUNCHER:
00328 default:
00329 break;
00330 case WP_THERMAL:
00331 case WP_BLASTER:
00332
00333
00334
00335 ST_ClearTimers( ent );
00336 if ( ent->NPC->rank >= RANK_LT || ent->client->ps.weapon == WP_THERMAL )
00337 {
00338
00339
00340 }
00341 break;
00342 }
00343 }
00344 if ( ent->client->NPC_class == CLASS_KYLE || ent->client->NPC_class == CLASS_VEHICLE || (ent->spawnflags & SFB_CINEMATIC) )
00345 {
00346 ent->NPC->defaultBehavior = BS_CINEMATIC;
00347 }
00348 else
00349 {
00350
00351
00352
00353
00354 }
00355 break;
00356
00357 case NPCTEAM_NEUTRAL:
00358
00359 if ( Q_stricmp( ent->NPC_type, "gonk" ) == 0 )
00360 {
00361
00362 ent->r.svFlags |= SVF_PLAYER_USABLE;
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380 }
00381 break;
00382
00383 case NPCTEAM_ENEMY:
00384 {
00385 ent->NPC->defaultBehavior = BS_DEFAULT;
00386 if ( ent->client->NPC_class == CLASS_SHADOWTROOPER )
00387 {
00388 Jedi_Cloak( ent );
00389 }
00390 if( ent->client->NPC_class == CLASS_TAVION ||
00391 ent->client->NPC_class == CLASS_REBORN ||
00392 ent->client->NPC_class == CLASS_DESANN ||
00393 ent->client->NPC_class == CLASS_SHADOWTROOPER )
00394 {
00395 ent->client->enemyTeam = NPCTEAM_PLAYER;
00396 if ( ent->spawnflags & JSF_AMBUSH )
00397 {
00398 ent->NPC->scriptFlags |= SCF_IGNORE_ALERTS;
00399 ent->client->noclip = qtrue;
00400 }
00401 }
00402 else if( ent->client->NPC_class == CLASS_PROBE || ent->client->NPC_class == CLASS_REMOTE ||
00403 ent->client->NPC_class == CLASS_INTERROGATOR || ent->client->NPC_class == CLASS_SENTRY)
00404 {
00405 ent->NPC->defaultBehavior = BS_DEFAULT;
00406 ent->client->ps.gravity = 0;
00407 ent->NPC->aiFlags |= NPCAI_CUSTOM_GRAVITY;
00408 ent->client->ps.eFlags2 |= EF2_FLYING;
00409 }
00410 else
00411 {
00412
00413 switch ( ent->client->ps.weapon )
00414 {
00415 case WP_BRYAR_PISTOL:
00416 break;
00417
00418
00419 case WP_DISRUPTOR:
00420
00421
00422 break;
00423 case WP_BOWCASTER:
00424 break;
00425 case WP_REPEATER:
00426
00427 break;
00428 case WP_DEMP2:
00429 break;
00430 case WP_FLECHETTE:
00431
00432 if ( !Q_stricmp( "stofficeralt", ent->NPC_type ) )
00433 {
00434
00435 }
00436 break;
00437 case WP_ROCKET_LAUNCHER:
00438 break;
00439 case WP_THERMAL:
00440
00441
00442 break;
00443 case WP_STUN_BATON:
00444 break;
00445 default:
00446 case WP_BLASTER:
00447
00448
00449 ST_ClearTimers( ent );
00450 if ( ent->NPC->rank >= RANK_COMMANDER )
00451 {
00452
00453 }
00454 if ( !Q_stricmp( "rodian2", ent->NPC_type ) )
00455 {
00456
00457 }
00458 break;
00459 }
00460 if ( !Q_stricmp( "galak_mech", ent->NPC_type ) )
00461 {
00462 NPC_GalakMech_Init( ent );
00463 }
00464 }
00465 }
00466 break;
00467
00468 default:
00469 break;
00470 }
00471
00472
00473 if ( ent->client->NPC_class == CLASS_SEEKER
00474 && ent->activator )
00475 {
00476 }
00477 else
00478 {
00479
00480 if (g_gametype.integer == GT_SIEGE && ent->s.NPC_class != CLASS_VEHICLE)
00481 {
00482 if (ent->client->enemyTeam == NPCTEAM_PLAYER)
00483 {
00484 ent->client->sess.sessionTeam = SIEGETEAM_TEAM1;
00485 }
00486 else if (ent->client->enemyTeam == NPCTEAM_ENEMY)
00487 {
00488 ent->client->sess.sessionTeam = SIEGETEAM_TEAM2;
00489 }
00490 else
00491 {
00492 ent->client->sess.sessionTeam = TEAM_FREE;
00493 }
00494 }
00495 }
00496
00497 if ( ent->client->NPC_class == CLASS_ATST || ent->client->NPC_class == CLASS_MARK1 )
00498 {
00499 ent->flags |= (FL_SHIELDED|FL_NO_KNOCKBACK);
00500 }
00501 }
00502
00503
00504
00505
00506
00507
00508
00509 int NPC_WeaponsForTeam( team_t team, int spawnflags, const char *NPC_type )
00510 {
00511
00512 switch(team)
00513 {
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528 case NPCTEAM_ENEMY:
00529 if ( Q_stricmp( "tavion", NPC_type ) == 0 ||
00530 Q_strncmp( "reborn", NPC_type, 6 ) == 0 ||
00531 Q_stricmp( "desann", NPC_type ) == 0 ||
00532 Q_strncmp( "shadowtrooper", NPC_type, 13 ) == 0 )
00533 return ( 1 << WP_SABER);
00534
00535
00536
00537
00538
00539
00540 if ( Q_strncmp( "stofficer", NPC_type, 9 ) == 0 )
00541 {
00542 return ( 1 << WP_FLECHETTE);
00543 }
00544 if ( Q_stricmp( "stcommander", NPC_type ) == 0 )
00545 {
00546 return ( 1 << WP_REPEATER);
00547 }
00548 if ( Q_stricmp( "swamptrooper", NPC_type ) == 0 )
00549 {
00550 return ( 1 << WP_FLECHETTE);
00551 }
00552 if ( Q_stricmp( "swamptrooper2", NPC_type ) == 0 )
00553 {
00554 return ( 1 << WP_REPEATER);
00555 }
00556 if ( Q_stricmp( "rockettrooper", NPC_type ) == 0 )
00557 {
00558 return ( 1 << WP_ROCKET_LAUNCHER);
00559 }
00560 if ( Q_strncmp( "shadowtrooper", NPC_type, 13 ) == 0 )
00561 {
00562 return ( 1 << WP_SABER);
00563 }
00564 if ( Q_stricmp( "imperial", NPC_type ) == 0 )
00565 {
00566
00567 return ( 1 << WP_BLASTER);
00568 }
00569 if ( Q_strncmp( "impworker", NPC_type, 9 ) == 0 )
00570 {
00571
00572 return ( 1 << WP_BLASTER);
00573 }
00574 if ( Q_stricmp( "stormpilot", NPC_type ) == 0 )
00575 {
00576
00577 return ( 1 << WP_BLASTER);
00578 }
00579 if ( Q_stricmp( "galak", NPC_type ) == 0 )
00580 {
00581 return ( 1 << WP_BLASTER);
00582 }
00583 if ( Q_stricmp( "galak_mech", NPC_type ) == 0 )
00584 {
00585 return ( 1 << WP_REPEATER);
00586 }
00587 if ( Q_strncmp( "ugnaught", NPC_type, 8 ) == 0 )
00588 {
00589 return WP_NONE;
00590 }
00591 if ( Q_stricmp( "granshooter", NPC_type ) == 0 )
00592 {
00593 return ( 1 << WP_BLASTER);
00594 }
00595 if ( Q_stricmp( "granboxer", NPC_type ) == 0 )
00596 {
00597 return ( 1 << WP_STUN_BATON);
00598 }
00599 if ( Q_strncmp( "gran", NPC_type, 4 ) == 0 )
00600 {
00601 return (( 1 << WP_THERMAL)|( 1 << WP_STUN_BATON));
00602 }
00603 if ( Q_stricmp( "rodian", NPC_type ) == 0 )
00604 {
00605 return ( 1 << WP_DISRUPTOR);
00606 }
00607 if ( Q_stricmp( "rodian2", NPC_type ) == 0 )
00608 {
00609 return ( 1 << WP_BLASTER);
00610 }
00611
00612 if (( Q_stricmp( "interrogator",NPC_type) == 0) || ( Q_stricmp( "sentry",NPC_type) == 0) || (Q_strncmp( "protocol",NPC_type,8) == 0) )
00613 {
00614 return WP_NONE;
00615 }
00616
00617 if ( Q_strncmp( "weequay", NPC_type, 7 ) == 0 )
00618 {
00619 return ( 1 << WP_BOWCASTER);
00620 }
00621 if ( Q_stricmp( "impofficer", NPC_type ) == 0 )
00622 {
00623 return ( 1 << WP_BLASTER);
00624 }
00625 if ( Q_stricmp( "impcommander", NPC_type ) == 0 )
00626 {
00627 return ( 1 << WP_BLASTER);
00628 }
00629 if (( Q_stricmp( "probe", NPC_type ) == 0 ) || ( Q_stricmp( "seeker", NPC_type ) == 0 ))
00630 {
00631
00632 return 0;
00633 }
00634 if ( Q_stricmp( "remote", NPC_type ) == 0 )
00635 {
00636
00637 return 0;
00638 }
00639 if ( Q_stricmp( "trandoshan", NPC_type ) == 0 )
00640 {
00641 return (1<<WP_REPEATER);
00642 }
00643 if ( Q_stricmp( "atst", NPC_type ) == 0 )
00644 {
00645
00646 return 0;
00647 }
00648 if ( Q_stricmp( "mark1", NPC_type ) == 0 )
00649 {
00650
00651 return 0;
00652 }
00653 if ( Q_stricmp( "mark2", NPC_type ) == 0 )
00654 {
00655
00656 return 0;
00657 }
00658 if ( Q_stricmp( "minemonster", NPC_type ) == 0 )
00659 {
00660 return (( 1 << WP_STUN_BATON));
00661 }
00662 if ( Q_stricmp( "howler", NPC_type ) == 0 )
00663 {
00664 return (( 1 << WP_STUN_BATON));
00665 }
00666
00667 return ( 1 << WP_BLASTER);
00668 break;
00669
00670 case NPCTEAM_PLAYER:
00671
00672
00673
00674
00675 if(spawnflags & SFB_RIFLEMAN)
00676 return ( 1 << WP_REPEATER);
00677
00678 if(spawnflags & SFB_PHASER)
00679
00680 return ( 1 << WP_BLASTER);
00681
00682 if ( Q_strncmp( "jedi", NPC_type, 4 ) == 0 || Q_stricmp( "luke", NPC_type ) == 0 )
00683 return ( 1 << WP_SABER);
00684
00685 if ( Q_strncmp( "prisoner", NPC_type, 8 ) == 0 )
00686 {
00687 return WP_NONE;
00688 }
00689 if ( Q_strncmp( "bespincop", NPC_type, 9 ) == 0 )
00690 {
00691
00692 return ( 1 << WP_BLASTER);
00693 }
00694
00695 if ( Q_stricmp( "MonMothma", NPC_type ) == 0 )
00696 {
00697 return WP_NONE;
00698 }
00699
00700
00701 return ( 1 << WP_BLASTER);
00702 break;
00703
00704 case NPCTEAM_NEUTRAL:
00705
00706 if ( Q_stricmp( "mark1", NPC_type ) == 0 )
00707 {
00708 return WP_NONE;
00709 }
00710 if ( Q_stricmp( "mark2", NPC_type ) == 0 )
00711 {
00712 return WP_NONE;
00713 }
00714 if ( Q_strncmp( "ugnaught", NPC_type, 8 ) == 0 )
00715 {
00716 return WP_NONE;
00717 }
00718 if ( Q_stricmp( "bartender", NPC_type ) == 0 )
00719 {
00720 return WP_NONE;
00721 }
00722 if ( Q_stricmp( "morgankatarn", NPC_type ) == 0 )
00723 {
00724 return WP_NONE;
00725 }
00726
00727 break;
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744 default:
00745 break;
00746 }
00747
00748 return WP_NONE;
00749 }
00750
00751 extern void ChangeWeapon( gentity_t *ent, int newWeapon );
00752
00753
00754
00755
00756
00757
00758
00759 void NPC_SetWeapons( gentity_t *ent )
00760 {
00761 int bestWeap = WP_NONE;
00762 int curWeap;
00763 int weapons = NPC_WeaponsForTeam( ent->client->playerTeam, ent->spawnflags, ent->NPC_type );
00764
00765 ent->client->ps.stats[STAT_WEAPONS] = 0;
00766 for ( curWeap = WP_SABER; curWeap < WP_NUM_WEAPONS; curWeap++ )
00767 {
00768 if ( (weapons & ( 1 << curWeap )) )
00769 {
00770 ent->client->ps.stats[STAT_WEAPONS] |= ( 1 << curWeap );
00771
00772
00773 ent->NPC->currentAmmo = ent->client->ps.ammo[weaponData[curWeap].ammoIndex] = 100;
00774
00775 if ( bestWeap == WP_SABER )
00776 {
00777
00778 continue;
00779 }
00780
00781 if ( curWeap == WP_STUN_BATON )
00782 {
00783 if ( bestWeap == WP_NONE )
00784 {
00785 bestWeap = curWeap;
00786 }
00787 }
00788 else if ( curWeap > bestWeap || bestWeap == WP_STUN_BATON )
00789 {
00790
00791 bestWeap = curWeap;
00792 }
00793 }
00794 }
00795
00796 ent->client->ps.weapon = bestWeap;
00797 }
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808 void NPC_SpawnEffect (gentity_t *ent)
00809 {
00810 }
00811
00812
00813
00814
00815
00816
00817 void NPC_SetFX_SpawnStates( gentity_t *ent )
00818 {
00819 if ( !(ent->NPC->aiFlags&NPCAI_CUSTOM_GRAVITY) )
00820 {
00821 ent->client->ps.gravity = g_gravity.value;
00822 }
00823 }
00824
00825
00826
00827
00828
00829
00830
00831 qboolean NPC_SpotWouldTelefrag( gentity_t *npc )
00832 {
00833 int i, num;
00834 int touch[MAX_GENTITIES];
00835 gentity_t *hit;
00836 vec3_t mins, maxs;
00837
00838 VectorAdd( npc->r.currentOrigin, npc->r.mins, mins );
00839 VectorAdd( npc->r.currentOrigin, npc->r.maxs, maxs );
00840 num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
00841
00842 for (i=0 ; i<num ; i++)
00843 {
00844 hit = &g_entities[touch[i]];
00845
00846 if (hit->inuse
00847 && hit->client
00848 && hit->s.number != npc->s.number
00849 && (hit->r.contents&MASK_NPCSOLID)
00850 && hit->s.number != npc->r.ownerNum
00851 && hit->r.ownerNum != npc->s.number)
00852 {
00853 return qtrue;
00854 }
00855
00856 }
00857
00858 return qfalse;
00859 }
00860
00861
00862 void NPC_Begin (gentity_t *ent)
00863 {
00864 vec3_t spawn_origin, spawn_angles;
00865 gclient_t *client;
00866 usercmd_t ucmd;
00867 gentity_t *spawnPoint = NULL;
00868
00869 memset( &ucmd, 0, sizeof( ucmd ) );
00870
00871 if ( !(ent->spawnflags & SFB_NOTSOLID) )
00872 {
00873 if (NPC_SpotWouldTelefrag(ent))
00874 {
00875 if ( ent->wait < 0 )
00876 {
00877 G_DebugPrint( WL_DEBUG, "NPC %s could not spawn, firing target3 (%s) and removing self\n", ent->targetname, ent->target3 );
00878
00879 G_UseTargets2( ent, ent, ent->target3 );
00880
00881
00882 ent->think = G_FreeEntity;
00883 ent->nextthink = level.time + 100;
00884 }
00885 else
00886 {
00887 G_DebugPrint( WL_DEBUG, "NPC %s could not spawn, waiting %4.2 secs to try again\n", ent->targetname, ent->wait/1000.0f );
00888 ent->think = NPC_Begin;
00889 ent->nextthink = level.time + ent->wait;
00890 }
00891 return;
00892 }
00893 }
00894
00895 NPC_SpawnEffect( ent );
00896
00897 VectorCopy( ent->client->ps.origin, spawn_origin);
00898 VectorCopy( ent->s.angles, spawn_angles);
00899 spawn_angles[YAW] = ent->NPC->desiredYaw;
00900
00901 client = ent->client;
00902
00903
00904 client->ps.persistant[PERS_SPAWN_COUNT]++;
00905
00906 client->airOutTime = level.time + 12000;
00907
00908 client->ps.clientNum = ent->s.number;
00909
00910
00911 if ( ent->health )
00912 {
00913 client->pers.maxHealth = client->ps.stats[STAT_MAX_HEALTH] = ent->health;
00914 }
00915 else if ( ent->NPC->stats.health )
00916 {
00917
00918 if ( ent->client->NPC_class != CLASS_REBORN
00919 && ent->client->NPC_class != CLASS_SHADOWTROOPER
00920
00921
00922 && ent->client->NPC_class != CLASS_JEDI )
00923 {
00924 ent->NPC->stats.health += ent->NPC->stats.health/4 * g_spskill.integer;
00925 }
00926
00927 client->pers.maxHealth = client->ps.stats[STAT_MAX_HEALTH] = ent->NPC->stats.health;
00928 }
00929 else
00930 {
00931 client->pers.maxHealth = client->ps.stats[STAT_MAX_HEALTH] = 100;
00932 }
00933
00934 if ( !Q_stricmp( "rodian", ent->NPC_type ) )
00935 {
00936
00937 switch ( g_spskill.integer )
00938 {
00939 case 0:
00940 ent->NPC->stats.aim = 1;
00941 break;
00942 case 1:
00943 ent->NPC->stats.aim = Q_irand( 2, 3 );
00944 break;
00945 case 2:
00946 ent->NPC->stats.aim = Q_irand( 3, 4 );
00947 break;
00948 }
00949 }
00950 else if ( ent->client->NPC_class == CLASS_STORMTROOPER
00951 || ent->client->NPC_class == CLASS_SWAMPTROOPER
00952 || ent->client->NPC_class == CLASS_IMPWORKER
00953 || !Q_stricmp( "rodian2", ent->NPC_type ) )
00954 {
00955 switch ( g_spskill.integer )
00956 {
00957 case 0:
00958 ent->NPC->stats.yawSpeed *= 0.75f;
00959 if ( ent->client->NPC_class == CLASS_IMPWORKER )
00960 {
00961 ent->NPC->stats.aim -= Q_irand( 3, 6 );
00962 }
00963 break;
00964 case 1:
00965 if ( ent->client->NPC_class == CLASS_IMPWORKER )
00966 {
00967 ent->NPC->stats.aim -= Q_irand( 2, 4 );
00968 }
00969 break;
00970 case 2:
00971 ent->NPC->stats.yawSpeed *= 1.5f;
00972 if ( ent->client->NPC_class == CLASS_IMPWORKER )
00973 {
00974 ent->NPC->stats.aim -= Q_irand( 0, 2 );
00975 }
00976 break;
00977 }
00978 }
00979 else if ( ent->client->NPC_class == CLASS_REBORN
00980 || ent->client->NPC_class == CLASS_SHADOWTROOPER )
00981 {
00982 switch ( g_spskill.integer )
00983 {
00984 case 1:
00985 ent->NPC->stats.yawSpeed *= 1.25f;
00986 break;
00987 case 2:
00988 ent->NPC->stats.yawSpeed *= 1.5f;
00989 break;
00990 }
00991 }
00992
00993
00994 ent->s.groundEntityNum = ENTITYNUM_NONE;
00995 ent->mass = 10;
00996 ent->takedamage = qtrue;
00997 ent->inuse = qtrue;
00998 ent->classname = "NPC";
00999
01000
01001
01002
01003
01004 if(!(ent->spawnflags & SFB_NOTSOLID))
01005 {
01006 ent->r.contents = CONTENTS_BODY;
01007 ent->clipmask = MASK_NPCSOLID;
01008 }
01009 else
01010 {
01011 ent->r.contents = 0;
01012 ent->clipmask = MASK_NPCSOLID&~CONTENTS_BODY;
01013 }
01014
01015
01016
01017
01018
01019
01020
01021
01022 ent->die = player_die;
01023 ent->waterlevel = 0;
01024 ent->watertype = 0;
01025 ent->client->ps.rocketLockIndex = ENTITYNUM_NONE;
01026 ent->client->ps.rocketLockTime = 0;
01027
01028
01029 if ( ent->client->NPC_class != CLASS_R2D2 &&
01030 ent->client->NPC_class != CLASS_R5D2 &&
01031 ent->client->NPC_class != CLASS_MOUSE &&
01032 ent->client->NPC_class != CLASS_GONK &&
01033 ent->client->NPC_class != CLASS_PROTOCOL )
01034 {
01035 ent->flags &= ~FL_NOTARGET;
01036 }
01037 ent->s.eFlags &= ~EF_NODRAW;
01038
01039 NPC_SetFX_SpawnStates( ent );
01040
01041
01042
01043
01044 if ( ent->client->ps.weapon == WP_NONE )
01045 {
01046 NPC_SetWeapons(ent);
01047 }
01048
01049 ent->NPC->currentAmmo = ent->client->ps.ammo[weaponData[ent->client->ps.weapon].ammoIndex];
01050 ent->client->ps.weaponstate = WEAPON_IDLE;
01051 ChangeWeapon( ent, ent->client->ps.weapon );
01052
01053 VectorCopy( spawn_origin, client->ps.origin );
01054
01055
01056 client->ps.pm_flags |= PMF_RESPAWNED;
01057
01058
01059
01060 ent->s.eType = ET_NPC;
01061
01062
01063 VectorCopy (spawn_origin, ent->s.origin);
01064
01065
01066 SetClientViewAngle( ent, spawn_angles );
01067 client->renderInfo.lookTarget = ENTITYNUM_NONE;
01068
01069 if(!(ent->spawnflags & 64))
01070 {
01071 G_KillBox( ent );
01072 trap_LinkEntity (ent);
01073 }
01074
01075
01076 client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
01077 client->ps.pm_time = 100;
01078
01079 client->respawnTime = level.time;
01080 client->inactivityTime = level.time + g_inactivity.value * 1000;
01081 client->latched_buttons = 0;
01082 if ( ent->s.m_iVehicleNum )
01083 {
01084 }
01085 else if ( client->NPC_class == CLASS_SEEKER && ent->activator != NULL )
01086 {
01087 ent->s.owner = ent->r.ownerNum = ent->activator->s.number;
01088 }
01089 else
01090 {
01091 ent->s.owner = ENTITYNUM_NONE;
01092 }
01093
01094
01095 if ( ent->client->NPC_class != CLASS_VEHICLE )
01096 {
01097 NPC_SetAnim( ent, SETANIM_BOTH, BOTH_STAND1, SETANIM_FLAG_NORMAL );
01098 }
01099
01100 if( spawnPoint )
01101 {
01102
01103 G_UseTargets( spawnPoint, ent );
01104 }
01105
01106
01107 trap_ICARUS_InitEnt( ent );
01108
01109
01110 SetNPCGlobals( ent );
01111
01112 ent->enemy = NULL;
01113 NPCInfo->timeOfDeath = 0;
01114 NPCInfo-