codemp/game/NPC_spawn.c

Go to the documentation of this file.
00001 //b_spawn.cpp
00002 //added by MCG
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 //extern void FX_BorgTeleport( vec3_t org );
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 //extern void CG_ShimmeryThing_Spawner( vec3_t start, vec3_t end, float radius, qboolean taper, int duration );
00024 
00025 //extern void NPC_StasisSpawnEffect( gentity_t *ent );
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 // PAIN functions...
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 //void HirogenAlpha_Precache( void );
00089 
00090 int WP_SetSaberModel( gclient_t *client, class_t npcClass )
00091 {
00092         //rwwFIXMEFIXME: Do something here, need to let the client know.
00093         return 1;
00094 }
00095 
00096 /*
00097 -------------------------
00098 NPC_PainFunc
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                 // team no longer indicates race/species, use NPC_class to determine different npc types
00114                 /*
00115                 switch ( ent->client->playerTeam )
00116                 {
00117                 default:
00118                         func = painF_NPC_Pain;
00119                         break;
00120                 }
00121                 */
00122                 switch( ent->client->NPC_class )
00123                 {
00124                 // troopers get special pain
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                 // all other droids, did I miss any?
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                 // everyone else gets the normal pain func
00181                 default:
00182                         func = NPC_Pain;
00183                         break;
00184                 }
00185 
00186         }
00187 
00188         return func;
00189 }
00190 
00191 
00192 /*
00193 -------------------------
00194 NPC_TouchFunc
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 NPC_SetMiscDefaultData
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         {//if a cinematic guy, default us to wait bState
00219                 ent->NPC->behaviorState = BS_CINEMATIC;
00220         }
00221         if ( ent->client->NPC_class == CLASS_BOBAFETT )
00222         {//set some stuff, precache
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         //if ( !Q_stricmp( "atst_vehicle", ent->NPC_type ) )//FIXME: has to be a better, easier way to tell this, no?
00230         if (ent->s.NPC_class == CLASS_VEHICLE && ent->m_pVehicle)
00231         {
00232                 ent->s.g2radius = 255;//MAX for this value, was (ent->r.maxs[2]-ent->r.mins[2]), which is 272 or something
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                 //turn the damn hatch cover on and LEAVE it on
00241                 trap_G2API_SetSurfaceOnOff( ent->ghoul2, "head_hatchcover", 0/*TURN_ON*/ );
00242         }
00243         if ( !Q_stricmp( "wampa", ent->NPC_type ) )
00244         {//FIXME: extern this into NPC.cfg?
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;//MAX for this value, was (ent->r.maxs[2]-ent->r.mins[2]), which is 272 or something
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         {//FIXME: extern this into NPC.cfg?
00262                 ent->NPC->scriptFlags |= SCF_NO_FORCE;//force powers don't work on him
00263         }
00264         if ( !Q_stricmp( "emperor", ent->NPC_type ) )
00265         {//FIXME: extern this into NPC.cfg?
00266                 ent->NPC->scriptFlags |= SCF_DONT_FIRE;//so he uses only force powers
00267         }
00268         //==================
00269 //      if ( ent->client->ps.saber[0].type != SABER_NONE )
00270         if (ent->client->ps.weapon == WP_SABER) //rwwFIXMEFIXME: is this going to work?
00271         {//if I'm equipped with a saber, initialize it (them)
00272         //      ent->client->ps.SaberDeactivate();
00273         //      ent->client->ps.SetSaberLength( 0 );
00274                 WP_SaberInitBladeData( ent );
00275                 ent->client->ps.saberHolstered = 2;
00276         //      G_CreateG2AttachedWeaponModel( ent, ent->client->ps.saber[0].model, ent->handRBolt, 0 );
00277         //      if ( ent->client->ps.dualSabers )
00278         //      {
00279         //              G_CreateG2AttachedWeaponModel( ent, ent->client->ps.saber[1].model, ent->handLBolt, 1 );
00280         //      }
00281                 Jedi_ClearTimers( ent );
00282         }
00283         if ( ent->client->ps.fd.forcePowersKnown != 0 )
00284         {
00285                 WP_InitForcePowers( ent );
00286                 WP_SpawnInitForcePowers(ent); //rww
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; // SEEKER shot ammo count
00295         }
00296         //***I'm not sure whether I should leave this as a TEAM_ switch, I think NPC_class may be more appropriate - dmv
00297         switch(ent->client->playerTeam)
00298         {
00299         case NPCTEAM_PLAYER:
00300                 //ent->flags |= FL_NO_KNOCKBACK;
00301                 if ( ent->client->NPC_class == CLASS_JEDI || ent->client->NPC_class == CLASS_LUKE )
00302                 {//good jedi
00303                         ent->client->enemyTeam = NPCTEAM_ENEMY;
00304                         if ( ent->spawnflags & JSF_AMBUSH )
00305                         {//ambusher
00306                                 ent->NPC->scriptFlags |= SCF_IGNORE_ALERTS;
00307                                 ent->client->noclip = qtrue;//hang
00308                         }
00309                 }
00310                 else
00311                 {
00312                         /*
00313                         if (ent->client->ps.weapon != WP_NONE)
00314                         {
00315                                 G_CreateG2AttachedWeaponModel( ent, weaponData[ent->client->ps.weapon].weaponMdl, ent->handRBolt, 0 );
00316                         }
00317                         */
00318                         switch ( ent->client->ps.weapon )
00319                         {
00320                         case WP_BRYAR_PISTOL://FIXME: new weapon: imp blaster pistol
00321         //              case WP_BLASTER_PISTOL:
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                                 //FIXME: health in NPCs.cfg, and not all blaster users are stormtroopers
00333                                 //ent->health = 25;
00334                                 //FIXME: not necc. a ST
00335                                 ST_ClearTimers( ent );
00336                                 if ( ent->NPC->rank >= RANK_LT || ent->client->ps.weapon == WP_THERMAL )
00337                                 {//officers, grenade-throwers use alt-fire
00338                                         //ent->health = 50;
00339                                         //ent->NPC->scriptFlags |= SCF_ALT_FIRE;
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                         ent->NPC->defaultBehavior = BS_FOLLOW_LEADER;
00352                         ent->client->leader = &g_entities[0];
00353                         */
00354                 }
00355                 break;
00356 
00357         case NPCTEAM_NEUTRAL: 
00358 
00359                 if ( Q_stricmp( ent->NPC_type, "gonk" ) == 0 ) 
00360                 {
00361                         // I guess we generically make them player usable
00362                         ent->r.svFlags |= SVF_PLAYER_USABLE;
00363 
00364                         // Not even sure if we want to give different levels of batteries?  ...Or even that these are the values we'd want to use.
00365                         /*
00366                         switch ( g_spskill.integer )
00367                         {
00368                         case 0: //      EASY
00369                                 ent->client->ps.batteryCharge = MAX_BATTERIES * 0.8f; 
00370                                 break;
00371                         case 1: //      MEDIUM
00372                                 ent->client->ps.batteryCharge = MAX_BATTERIES * 0.75f; 
00373                                 break;
00374                         default :
00375                         case 2: //      HARD
00376                                 ent->client->ps.batteryCharge = MAX_BATTERIES * 0.5f; 
00377                                 break;
00378                         }*/
00379                         //rwwFIXMEFIXME: Make use of this.
00380                 }
00381                 break;
00382 
00383         case NPCTEAM_ENEMY:
00384                 {
00385                         ent->NPC->defaultBehavior = BS_DEFAULT;
00386                         if ( ent->client->NPC_class == CLASS_SHADOWTROOPER )
00387                         {//FIXME: a spawnflag?
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                                 {//ambusher
00398                                         ent->NPC->scriptFlags |= SCF_IGNORE_ALERTS;
00399                                         ent->client->noclip = qtrue;//hang
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                 //              G_CreateG2AttachedWeaponModel( ent, weaponData[ent->client->ps.weapon].weaponMdl, ent->handRBolt, 0 );
00413                                 switch ( ent->client->ps.weapon )
00414                                 {
00415                                 case WP_BRYAR_PISTOL:
00416                                         break;
00417                 //              case WP_BLASTER_PISTOL:
00418                 //                      break;
00419                                 case WP_DISRUPTOR:
00420                                         //Sniper
00421                                         //ent->NPC->scriptFlags |= SCF_ALT_FIRE;//FIXME: use primary fire sometimes?  Up close?  Different class of NPC?
00422                                         break;
00423                                 case WP_BOWCASTER:
00424                                         break;
00425                                 case WP_REPEATER:
00426                                         //machine-gunner
00427                                         break;
00428                                 case WP_DEMP2:
00429                                         break;
00430                                 case WP_FLECHETTE:
00431                                         //shotgunner
00432                                         if ( !Q_stricmp( "stofficeralt", ent->NPC_type ) )
00433                                         {
00434                                                 //ent->NPC->scriptFlags |= SCF_ALT_FIRE;
00435                                         }
00436                                         break;
00437                                 case WP_ROCKET_LAUNCHER:
00438                                         break;
00439                                 case WP_THERMAL:
00440                                         //Gran, use main, bouncy fire
00441 //                                      ent->NPC->scriptFlags |= SCF_ALT_FIRE;
00442                                         break;
00443                                 case WP_STUN_BATON:
00444                                         break;
00445                                 default:
00446                                 case WP_BLASTER:
00447                                         //FIXME: health in NPCs.cfg, and not all blaster users are stormtroopers
00448                                         //FIXME: not necc. a ST
00449                                         ST_ClearTimers( ent );
00450                                         if ( ent->NPC->rank >= RANK_COMMANDER )
00451                                         {//commanders use alt-fire
00452                                                 //ent->NPC->scriptFlags |= SCF_ALT_FIRE;
00453                                         }
00454                                         if ( !Q_stricmp( "rodian2", ent->NPC_type ) )
00455                                         {
00456                                                 //ent->NPC->scriptFlags |= SCF_ALT_FIRE;
00457                                         }
00458                                         break;
00459                                 }
00460                                 if ( !Q_stricmp( "galak_mech", ent->NPC_type ) )
00461                                 {//starts with armor
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         {//assume my teams are already set correctly
00476         }
00477         else
00478         {
00479                 //for siege, want "bad" npc's allied with the "bad" team
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 ) // chris/steve/kevin requested that the mark1 be shielded also
00498         {
00499                 ent->flags |= (FL_SHIELDED|FL_NO_KNOCKBACK);
00500         }
00501 }
00502 
00503 /*
00504 -------------------------
00505 NPC_WeaponsForTeam
00506 -------------------------
00507 */
00508 
00509 int NPC_WeaponsForTeam( team_t team, int spawnflags, const char *NPC_type )
00510 {
00511         //*** not sure how to handle this, should I pass in class instead of team and go from there? - dmv
00512         switch(team)
00513         {
00514         // no longer exists
00515 //      case TEAM_BORG:
00516 //              break;
00517 
00518 //      case TEAM_HIROGEN:
00519 //              if( Q_stricmp( "hirogenalpha", NPC_type ) == 0 )
00520 //                      return ( 1 << WP_BLASTER);
00521                 //Falls through
00522 
00523 //      case TEAM_KLINGON:
00524 
00525                 //NOTENOTE: Falls through
00526 
00527 //      case TEAM_IMPERIAL:
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 //                      return ( 1 << WP_IMPERIAL_BLADE);
00535                 //NOTENOTE: Falls through if not a knife user
00536 
00537 //      case TEAM_SCAVENGERS:
00538 //      case TEAM_MALON:
00539                 //FIXME: default weapon in npc config?
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);//|( 1 << WP_RAPID_CONCUSSION)?
00563                 }
00564                 if ( Q_stricmp( "imperial", NPC_type ) == 0 )
00565                 {
00566                         //return ( 1 << WP_BLASTER_PISTOL);
00567                         return ( 1 << WP_BLASTER);
00568                 }
00569                 if ( Q_strncmp( "impworker", NPC_type, 9 ) == 0 )
00570                 {
00571                         //return ( 1 << WP_BLASTER_PISTOL);
00572                         return ( 1 << WP_BLASTER);
00573                 }
00574                 if ( Q_stricmp( "stormpilot", NPC_type ) == 0 )
00575                 {
00576                         //return ( 1 << WP_BLASTER_PISTOL);
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);//|( 1 << WP_STAFF )(FIXME: new weap?)
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                         //return ( 1 << WP_BOT_LASER);
00632                         return 0;
00633                 }       
00634                 if ( Q_stricmp( "remote", NPC_type ) == 0 )
00635                 {
00636                         //return ( 1 << WP_BOT_LASER );
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                         //return (( 1 << WP_ATST_MAIN)|( 1 << WP_ATST_SIDE));
00646                         return 0;
00647                 }
00648                 if ( Q_stricmp( "mark1", NPC_type ) == 0 )
00649                 {
00650                         //return ( 1 << WP_BOT_LASER);
00651                         return 0;
00652                 }
00653                 if ( Q_stricmp( "mark2", NPC_type ) == 0 )
00654                 {
00655                         //return ( 1 << WP_BOT_LASER);
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                 //Stormtroopers, etc.
00667                 return ( 1 << WP_BLASTER);
00668                 break;
00669 
00670         case NPCTEAM_PLAYER:
00671                 
00672 //              if(spawnflags & SFB_TRICORDER)
00673 //                      return ( 1 << WP_TRICORDER);
00674                 
00675                 if(spawnflags & SFB_RIFLEMAN)
00676                         return ( 1 << WP_REPEATER);
00677                 
00678                 if(spawnflags & SFB_PHASER)
00679                         //return ( 1 << WP_BLASTER_PISTOL);
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                         //return ( 1 << WP_BLASTER_PISTOL);
00692                         return ( 1 << WP_BLASTER);
00693                 }
00694 
00695                 if ( Q_stricmp( "MonMothma", NPC_type ) == 0 )
00696                 {
00697                         return WP_NONE;
00698                 }
00699 
00700                 //rebel
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         // these no longer exist
00730 //      case TEAM_FORGE:
00731 //              return ( 1 << WP_STUN_BATON);
00732 //              break;
00733 
00734 //      case TEAM_STASIS:
00735 //              return ( 1 << WP_STUN_BATON);
00736 //              break;
00737 
00738 //      case TEAM_PARASITE:
00739 //              break;
00740 
00741 //      case TEAM_8472:
00742 //              break;
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 NPC_SetWeapons
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 //                      RegisterItem( FindItemForWeapon( (weapon_t)(curWeap) ) );       //precache the weapon
00772                         //rwwFIXMEFIXME: Precache
00773                         ent->NPC->currentAmmo = ent->client->ps.ammo[weaponData[curWeap].ammoIndex] = 100;//FIXME: max ammo
00774 
00775                         if ( bestWeap == WP_SABER )
00776                         {
00777                                 // still want to register other weapons -- force saber to be best weap
00778                                 continue;
00779                         }
00780 
00781                         if ( curWeap == WP_STUN_BATON )
00782                         {
00783                                 if ( bestWeap == WP_NONE )
00784                                 {// We'll only consider giving Melee since we haven't found anything better yet.
00785                                         bestWeap = curWeap;
00786                                 }
00787                         }
00788                         else if ( curWeap > bestWeap || bestWeap == WP_STUN_BATON )
00789                         {
00790                                 // This will never override saber as best weap.  Also will override WP_STUN_BATON if something better comes later in the list
00791                                 bestWeap = curWeap;
00792                         }
00793                 }
00794         }
00795 
00796         ent->client->ps.weapon = bestWeap;
00797 }
00798 
00799 /*
00800 -------------------------
00801 NPC_SpawnEffect
00802 
00803   NOTE:  Make sure any effects called here have their models, tga's and sounds precached in
00804                         CG_RegisterNPCEffects in cg_player.cpp
00805 -------------------------
00806 */
00807 
00808 void NPC_SpawnEffect (gentity_t *ent)
00809 {
00810 }
00811 
00812 //--------------------------------------------------------------
00813 // NPC_SetFX_SpawnStates
00814 //
00815 // Set up any special parms for spawn effects
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 NPC_SpotWouldTelefrag
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                 //if ( hit->client && hit->client->ps.stats[STAT_HEALTH] > 0 ) {
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         {//No NPCs should telefrag
00873                 if (NPC_SpotWouldTelefrag(ent))
00874                 {
00875                         if ( ent->wait < 0 )
00876                         {//remove yourself
00877                                 G_DebugPrint( WL_DEBUG, "NPC %s could not spawn, firing target3 (%s) and removing self\n", ent->targetname, ent->target3 );
00878                                 //Fire off our target3
00879                                 G_UseTargets2( ent, ent, ent->target3 );
00880 
00881                                 //Kill us
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;//try again in half a second
00890                         }
00891                         return;
00892                 }
00893         }
00894         //Spawn effect
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         // increment the spawncount so the client will detect the respawn
00904         client->ps.persistant[PERS_SPAWN_COUNT]++;
00905 
00906         client->airOutTime = level.time + 12000;
00907 
00908         client->ps.clientNum = ent->s.number;
00909         // clear entity values
00910 
00911         if ( ent->health )      // Was health supplied in map
00912         {
00913                 client->pers.maxHealth = client->ps.stats[STAT_MAX_HEALTH] = ent->health;
00914         }
00915         else if ( ent->NPC->stats.health )      // Was health supplied in NPC.cfg?
00916         {
00917                 
00918                 if ( ent->client->NPC_class != CLASS_REBORN
00919                         && ent->client->NPC_class != CLASS_SHADOWTROOPER 
00920                         //&& ent->client->NPC_class != CLASS_TAVION
00921                         //&& ent->client->NPC_class != CLASS_DESANN 
00922                         && ent->client->NPC_class != CLASS_JEDI )
00923                 {// up everyone except jedi
00924                         ent->NPC->stats.health += ent->NPC->stats.health/4 * g_spskill.integer; // 100% on easy, 125% on medium, 150% on hard
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         {//sniper
00936                 //NOTE: this will get overridden by any aim settings in their spawnscripts
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         {//tweak yawspeed for these NPCs based on difficulty
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 //      if ( ent->client->race == RACE_HOLOGRAM )
01000 //      {//can shoot through holograms, but not walk through them
01001 //              ent->contents = CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_ITEM;//contents_corspe to make them show up in ID and use traces
01002 //              ent->clipmask = MASK_NPCSOLID;
01003 //      } else
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         if(!ent->client->moveType)//Static?
01016         {
01017                 ent->client->moveType = MT_RUNJUMP;
01018         }
01019         */
01020         //rwwFIXMEFIXME: movetype support
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         //visible to player and NPCs
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         //client->ps.friction = 6;
01042         //rwwFIXMEFIXME: per ent friction?
01043 
01044         if ( ent->client->ps.weapon == WP_NONE )
01045         {//not set by the NPCs.cfg
01046                 NPC_SetWeapons(ent);
01047         }
01048         //select the weapon
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         // the respawned flag will be cleared after the attack and jump keys come up
01056         client->ps.pm_flags |= PMF_RESPAWNED;
01057 
01058         // clear entity state values
01059         //ent->s.eType = ET_PLAYER;
01060         ent->s.eType = ET_NPC;
01061 //      ent->s.skinNum = ent - g_entities - 1;  // used as index to get custom models
01062 
01063         VectorCopy (spawn_origin, ent->s.origin);
01064 //      ent->s.origin[2] += 1;  // make sure off ground
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         // don't allow full run speed for a bit
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         {//I'm an NPC in a vehicle (or a vehicle), I already have owner set
01084         }
01085         else if ( client->NPC_class == CLASS_SEEKER && ent->activator != NULL )
01086         {//somebody else "owns" me
01087                 ent->s.owner = ent->r.ownerNum = ent->activator->s.number;
01088         }
01089         else
01090         {
01091                 ent->s.owner = ENTITYNUM_NONE;
01092         }
01093 
01094         // set default animations
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                 // fire the targets of the spawn point
01103                 G_UseTargets( spawnPoint, ent );
01104         }
01105 
01106         //ICARUS include
01107         trap_ICARUS_InitEnt( ent );
01108 
01109 //==NPC initialization
01110         SetNPCGlobals( ent );
01111 
01112         ent->enemy = NULL;
01113         NPCInfo->timeOfDeath = 0;
01114         NPCInfo->shotTime = 0;
01115         NPC_ClearGoal();
01116         NPC_ChangeWeapon( ent->client->ps.weapon );
01117 
01118 //==Final NPC initialization
01119         ent->pain  = NPC_PainFunc( ent ); //painF_NPC_Pain;
01120         ent->touch = NPC_TouchFunc( ent ); //touchF_NPC_Touch;
01121 //      ent->NPC->side = 1;
01122 
01123         ent->client->ps.ping = ent->NPC->stats.reactions * 50;
01124 
01125         //MCG - Begin: NPC hacks
01126         //FIXME: Set the team correctly
01127         if (ent->s.NPC_class != CLASS_VEHICLE || g_gametype.integer != GT_SIEGE)
01128         {
01129                 ent->client->ps.persistant[PERS_TEAM] = ent->client->playerTeam;
01130         }
01131 
01132         ent->use   = NPC_Use;
01133         ent->think = NPC_Think;
01134         ent->nextthink = level.time + FRAMETIME + Q_irand(0, 100);
01135 
01136         NPC_SetMiscDefaultData( ent );
01137         if ( ent->health <= 0 )
01138         {
01139                 //ORIGINAL ID: health will count down towards max_health
01140                 ent->health = client->ps.stats[STAT_HEALTH] = ent->client->pers.maxHealth;
01141         }
01142         else
01143         {
01144                 client->ps.stats[STAT_HEALTH] = ent->health;
01145         }
01146 
01147         if (ent->s.shouldtarget)
01148         {
01149                 ent->maxHealth = ent->health;
01150                 G_ScaleNetHealth(ent);
01151         }
01152 
01153         ChangeWeapon( ent, ent->client->ps.weapon );//yes, again... sigh
01154 
01155         if ( !(ent->spawnflags & SFB_STARTINSOLID) )
01156         {//Not okay to start in solid
01157                 G_CheckInSolid( ent, qtrue );
01158         }
01159         VectorClear( ent->NPC->lastClearOrigin );
01160 
01161         //Run a script if you have one assigned to you
01162         if ( G_ActivateBehavior( ent, BSET_SPAWN ) )
01163         {
01164                 trap_ICARUS_MaintainTaskManager(ent->s.number);
01165         }
01166 
01167         VectorCopy( ent->r.currentOrigin, ent->client->renderInfo.eyePoint );
01168 
01169         // run a client frame to drop exactly to the floor,
01170         // initialize animations and other things
01171         memset( &ucmd, 0, sizeof( ucmd ) );
01172         //_VectorCopy( client->pers.cmd_angles, ucmd.angles );
01173         VectorCopy(client->pers.cmd.angles, ucmd.angles);
01174         
01175         ent->client->ps.groundEntityNum = ENTITYNUM_NONE;
01176 
01177         if ( ent->NPC->aiFlags & NPCAI_MATCHPLAYERWEAPON )
01178         {
01179                 //G_MatchPlayerWeapon( ent );
01180                 //rwwFIXMEFIXME: Use this? Probably doesn't really matter for MP.
01181         }
01182 
01183         ClientThink( ent->s.number, &ucmd );
01184 
01185         trap_LinkEntity( ent );
01186 
01187         if ( ent->client->playerTeam == NPCTEAM_ENEMY )
01188         {//valid enemy spawned
01189                 if ( !(ent->spawnflags&SFB_CINEMATIC) && ent->NPC->behaviorState != BS_CINEMATIC )
01190                 {//not a cinematic enemy
01191                         if ( g_entities[0].client )
01192                         {
01193                                 //g_entities[0].client->sess.missionStats.enemiesSpawned++;
01194                                 //rwwFIXMEFIXME: Do something here? And this is a rather strange place to be storing
01195                                 //this sort of data.
01196                         }
01197                 }
01198         }
01199         ent->waypoint = ent->NPC->homeWp = WAYPOINT_NONE;
01200 
01201         if ( ent->m_pVehicle )
01202         {//a vehicle
01203                 //check for droidunit
01204                 if ( ent->m_pVehicle->m_iDroidUnitTag != -1 )
01205                 {
01206                         char    *droidNPCType = NULL;
01207                         gentity_t *droidEnt = NULL;
01208                         if ( ent->model2 
01209                                 && ent->model2[0] )
01210                         {//specified on the NPC_Vehicle spawner ent
01211                                 droidNPCType = ent->model2;
01212                         }
01213                         else if ( ent->m_pVehicle->m_pVehicleInfo->droidNPC
01214                                 && ent->m_pVehicle->m_pVehicleInfo->droidNPC[0] )
01215                         {//specified in the vehicle's .veh file
01216                                 droidNPCType = ent->m_pVehicle->m_pVehicleInfo->droidNPC;
01217                         }
01218 
01219                         if ( droidNPCType != NULL )
01220                         {
01221                                 if ( Q_stricmp( "random", droidNPCType ) == 0
01222                                         || Q_stricmp( "default", droidNPCType ) == 0 )
01223                                 {//use default - R2D2 or R5D2
01224                                         if ( Q_irand( 0, 1 ) )
01225                                         {
01226                                                 droidNPCType = "r2d2";
01227                                         }
01228                                         else
01229                                         {
01230                                                 droidNPCType = "r5d2";
01231                                         }
01232                                 }
01233                                 droidEnt = NPC_SpawnType( ent, droidNPCType, NULL, qfalse );
01234                                 if ( droidEnt != NULL )
01235                                 {
01236                                         if ( droidEnt->client )
01237                                         {
01238                                                 droidEnt->client->ps.m_iVehicleNum =
01239                                                         droidEnt->s.m_iVehicleNum =
01240                                                         //droidEnt->s.otherEntityNum2 = 
01241                                                         droidEnt->s.owner = 
01242                                                         droidEnt->r.ownerNum = ent->s.number;
01243                                                 ent->m_pVehicle->m_pDroidUnit = (bgEntity_t *)droidEnt;
01244                                                 //SP way:
01245                                                 //droidEnt->s.m_iVehicleNum = ent->s.number;
01246                                                 //droidEnt->owner = ent;
01247                                                 VectorCopy( ent->r.currentOrigin, droidEnt->s.origin );
01248                                                 VectorCopy( ent->r.currentOrigin, droidEnt->client->ps.origin );
01249                                                 G_SetOrigin( droidEnt, droidEnt->s.origin );
01250                                                 trap_LinkEntity( droidEnt );
01251                                                 VectorCopy( ent->r.currentAngles, droidEnt->s.angles );
01252                                                 G_SetAngles( droidEnt, droidEnt->s.angles );
01253                                                 if ( droidEnt->NPC )
01254                                                 {
01255                                                         droidEnt->NPC->desiredYaw = droidEnt->s.angles[YAW];
01256                                                         droidEnt->NPC->desiredPitch = droidEnt->s.angles[PITCH];
01257                                                 }
01258                                                 droidEnt->flags |= FL_UNDYING;
01259                                         }
01260                                         else
01261                                         {//wtf?
01262                                                 G_FreeEntity( droidEnt );
01263                                         }
01264                                 }
01265                         }
01266                 }
01267         }
01268 }
01269 
01270 gNPC_t *gNPCPtrs[MAX_GENTITIES];
01271 
01272 gNPC_t *New_NPC_t(int entNum)
01273 {
01274         gNPC_t *ptr;
01275 
01276         if (!gNPCPtrs[entNum])
01277         {
01278                 gNPCPtrs[entNum] = (gNPC_t *)BG_Alloc (sizeof(gNPC_t));
01279         }
01280                 
01281         ptr = gNPCPtrs[entNum];
01282 
01283         if (ptr)
01284         {
01285                 // clear it...
01286                 //
01287                 memset(ptr, 0, sizeof( *ptr ) );
01288         }
01289 
01290         return ptr;
01291 }
01292 
01293 #ifdef _XBOX
01294 void NPC_NPCPtrsClear(void)
01295 {
01296         for(int i=0; i<MAX_GENTITIES; i++) {
01297                 gNPCPtrs[i] = NULL;
01298         }
01299 }
01300 #endif
01301 
01302 /*
01303 -------------------------
01304 NPC_StasisSpawn_Go
01305 -------------------------
01306 */
01307 /*      
01308 qboolean NPC_StasisSpawn_Go( gentity_t *ent )
01309 {
01310         //Setup an owner pointer if we need it
01311         if VALIDSTRING( ent->ownername )
01312         {
01313                 ent->parent = G_Find( NULL, FOFS( targetname ), ent->ownername );
01314                 
01315                 if ( ( ent->parent ) && ( ent->parent->health <= 0 ) )
01316                 {//our spawner thing is broken
01317                         if ( ent->target2 && ent->target2[0] )
01318                         {
01319                                 //Fire off our target2
01320                                 G_UseTargets2( ent, ent, ent->target2 );
01321 
01322                                 //Kill us
01323                                 ent->e_ThinkFunc = thinkF_G_FreeEntity;
01324                                 ent->nextthink = level.time + 100;
01325                         }
01326                         else
01327                         {
01328                                 //Try to spawn again in one second
01329                                 ent->e_ThinkFunc = thinkF_NPC_Spawn_Go;
01330                                 ent->nextthink = level.time + 1000;
01331                         }
01332                         return qfalse;
01333                 }
01334         }
01335 
01336         //Test for an entity blocking the spawn
01337         trace_t tr;
01338         trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, ent->s.number, MASK_NPCSOLID );
01339 
01340         //Can't have anything in the way
01341         if ( tr.allsolid || tr.startsolid )
01342         {
01343                 ent->nextthink = level.time + 1000;
01344                 return qfalse;
01345         }
01346 
01347         return qtrue;
01348 }
01349 */
01350 void NPC_DefaultScriptFlags( gentity_t *ent )
01351 {
01352         if ( !ent || !ent->NPC )
01353         {
01354                 return;
01355         }
01356         //Set up default script flags
01357         ent->NPC->scriptFlags = (SCF_CHASE_ENEMIES|SCF_LOOK_FOR_ENEMIES);
01358 }
01359 /*
01360 -------------------------
01361 NPC_Spawn_Go
01362 -------------------------
01363 */
01364 #include "../namespace_begin.h"
01365 extern void G_CreateAnimalNPC( Vehicle_t **pVeh, const char *strAnimalType );
01366 extern void G_CreateSpeederNPC( Vehicle_t **pVeh, const char *strType );
01367 extern void G_CreateWalkerNPC( Vehicle_t **pVeh, const char *strAnimalType );
01368 extern void G_CreateFighterNPC( Vehicle_t **pVeh, const char *strType );
01369 #include "../namespace_end.h"
01370 
01371 gentity_t *NPC_Spawn_Do( gentity_t *ent )
01372 {
01373         gentity_t       *newent = NULL;
01374         int                     index;
01375         vec3_t          saveOrg;
01376 
01377 /*      //Do extra code for stasis spawners
01378         if ( Q_stricmp( ent->classname, "NPC_Stasis" ) == 0 )
01379         {
01380                 if ( NPC_StasisSpawn_Go( ent ) == qfalse )
01381                         return;
01382         }
01383 */
01384 
01385         //Test for drop to floor
01386         if ( ent->spawnflags & NSF_DROP_TO_FLOOR )
01387         {
01388                 trace_t         tr;
01389                 vec3_t          bottom;
01390 
01391                 VectorCopy( ent->r.currentOrigin, saveOrg );
01392                 VectorCopy( ent->r.currentOrigin, bottom );
01393                 bottom[2] = MIN_WORLD_COORD;
01394                 trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, bottom, ent->s.number, MASK_NPCSOLID );
01395                 if ( !tr.allsolid && !tr.startsolid && tr.fraction < 1.0 )
01396                 {
01397                         G_SetOrigin( ent, tr.endpos );
01398                 }
01399         }
01400 
01401         //Check the spawner's count
01402         if( ent->count != -1 )
01403         {
01404                 ent->count--;
01405                 
01406                 if( ent->count <= 0 )
01407                 {
01408                         ent->use = 0;//never again
01409                         //FIXME: why not remove me...?  Because of all the string pointers?  Just do G_NewStrings?
01410                 }
01411         }
01412 
01413         newent = G_Spawn();
01414 
01415         if ( newent == NULL ) 
01416         {
01417                 Com_Printf ( S_COLOR_RED"ERROR: NPC G_Spawn failed\n" );
01418                 return NULL;
01419         }
01420         
01421         newent->fullName = ent->fullName;
01422 
01423         newent->NPC = New_NPC_t(newent->s.number);      
01424         if ( newent->NPC == NULL ) 
01425         {               
01426                 Com_Printf ( S_COLOR_RED"ERROR: NPC G_Alloc NPC failed\n" );            
01427                 goto finish;
01428                 return NULL;
01429         }       
01430 
01431         //newent->client = (gclient_s *)G_Alloc (sizeof(gclient_s));
01432         G_CreateFakeClient(newent->s.number, &newent->client);
01433 
01434         newent->NPC->tempGoal = G_Spawn();
01435         
01436         if ( newent->NPC->tempGoal == NULL ) 
01437         {
01438                 newent->NPC = NULL;
01439                 goto finish;
01440                 return NULL;
01441         }
01442 
01443         newent->NPC->tempGoal->classname = "NPC_goal";
01444         newent->NPC->tempGoal->parent = newent;
01445         newent->NPC->tempGoal->r.svFlags |= SVF_NOCLIENT;
01446 
01447         if ( newent->client == NULL ) 
01448         {
01449                 Com_Printf ( S_COLOR_RED"ERROR: NPC BG_Alloc client failed\n" );
01450                 goto finish;
01451                 return NULL;
01452         }
01453         
01454         memset ( newent->client, 0, sizeof(*newent->client) );
01455 
01456         //Assign the pointer for bg entity access
01457         newent->playerState = &newent->client->ps;
01458 
01459 //==NPC_Connect( newent, net_name );===================================
01460 
01461         if ( ent->NPC_type == NULL ) 
01462         {
01463                 ent->NPC_type = "random";
01464         }
01465         else
01466         {
01467                 ent->NPC_type = Q_strlwr( G_NewString( ent->NPC_type ) );
01468         }
01469 
01470         if ( ent->r.svFlags & SVF_NO_BASIC_SOUNDS )
01471         {
01472                 newent->r.svFlags |= SVF_NO_BASIC_SOUNDS;
01473         }
01474         if ( ent->r.svFlags & SVF_NO_COMBAT_SOUNDS )
01475         {
01476                 newent->r.svFlags |= SVF_NO_COMBAT_SOUNDS;
01477         }
01478         if ( ent->r.svFlags & SVF_NO_EXTRA_SOUNDS )
01479         {
01480                 newent->r.svFlags |= SVF_NO_EXTRA_SOUNDS;
01481         }
01482         
01483         if ( ent->message )
01484         {//has a key
01485                 newent->message = ent->message;//transfer the key name
01486                 newent->flags |= FL_NO_KNOCKBACK;//don't fall off ledges
01487         }
01488 
01489         // If this is a vehicle we need to see what kind it is so we properlly allocate it.
01490         if ( Q_stricmp( ent->classname, "NPC_Vehicle" ) == 0 )
01491         {
01492                 // Get the vehicle entry index.
01493                 int iVehIndex = BG_VehicleGetIndex( ent->NPC_type );
01494 
01495                 if ( iVehIndex == VEHICLE_NONE )
01496                 {
01497                         G_FreeEntity( newent );
01498                         //get rid of the spawner, too, I guess
01499                         G_FreeEntity( ent );
01500                         return NULL;
01501                 }
01502                 // NOTE: If you change/add any of these, update NPC_Spawn_f for the new vehicle you
01503                 // want to be able to spawn in manually.
01504 
01505                 // See what kind of vehicle this is and allocate it properly.
01506                 switch( g_vehicleInfo[iVehIndex].type )
01507                 {
01508                         case VH_ANIMAL:
01509                                 // Create the animal (making sure all it's data is initialized).
01510                                 G_CreateAnimalNPC( &newent->m_pVehicle, ent->NPC_type );
01511                                 break;
01512                         case VH_SPEEDER:
01513                                 // Create the speeder (making sure all it's data is initialized).
01514                                 G_CreateSpeederNPC( &newent->m_pVehicle, ent->NPC_type );
01515                                 break;
01516                         case VH_FIGHTER:
01517                                 // Create the fighter (making sure all it's data is initialized).
01518                                 G_CreateFighterNPC( &newent->m_pVehicle, ent->NPC_type );
01519                                 break;
01520                         case VH_WALKER:
01521                                 // Create the walker (making sure all it's data is initialized).
01522                                 G_CreateWalkerNPC( &newent->m_pVehicle, ent->NPC_type );
01523                                 break;
01524 
01525                         default:
01526                                 Com_Printf ( S_COLOR_RED "ERROR: Couldn't spawn NPC %s\n", ent->NPC_type );
01527                                 G_FreeEntity( newent );
01528                                 //get rid of the spawner, too, I guess
01529                                 G_FreeEntity( ent );
01530                                 return NULL;
01531                 }
01532 
01533                 assert(newent->m_pVehicle &&
01534                         newent->m_pVehicle->m_pVehicleInfo &&
01535                         newent->m_pVehicle->m_pVehicleInfo->Initialize);
01536 
01537                 //set up my happy prediction hack
01538                 newent->m_pVehicle->m_vOrientation = &newent->client->ps.vehOrientation[0];
01539 
01540                 // Setup the vehicle.
01541                 newent->m_pVehicle->m_pParentEntity = (bgEntity_t *)newent;
01542                 newent->m_pVehicle->m_pVehicleInfo->Initialize( newent->m_pVehicle );
01543 
01544                 //cache all the assets
01545                 newent->m_pVehicle->m_pVehicleInfo->RegisterAssets( newent->m_pVehicle );
01546                 //set the class
01547                 newent->client->NPC_class = CLASS_VEHICLE;
01548                 if ( g_vehicleInfo[iVehIndex].type == VH_FIGHTER )
01549                 {//FIXME: EXTERN!!!
01550                         newent->flags |= (FL_NO_KNOCKBACK|FL_SHIELDED|FL_DMG_BY_HEAVY_WEAP_ONLY);//don't get pushed around, blasters bounce off, only damage from heavy weaps
01551                 }
01552                 //WTF?!!! Ships spawning in pointing straight down!
01553                 //set them up to start landed
01554                 newent->m_pVehicle->m_vOrientation[YAW] = ent->s.angles[YAW];
01555                 newent->m_pVehicle->m_vOrientation[PITCH] = newent->m_pVehicle->m_vOrientation[ROLL] = 0.0f;
01556                 G_SetAngles( newent, newent->m_pVehicle->m_vOrientation );
01557                 SetClientViewAngle( newent, newent->m_pVehicle->m_vOrientation );
01558 
01559                 //newent->m_pVehicle->m_ulFlags |= VEH_GEARSOPEN;
01560                 //why? this would just make it so the initial anim never got played... -rww
01561                 //There was no initial anim, it would just open the gear even though it's already on the ground (fixed now, made an initial anim)
01562                 
01563                 //For SUSPEND spawnflag, the amount of time to drop like a rock after SUSPEND turns off
01564                 newent->fly_sound_debounce_time = ent->fly_sound_debounce_time;
01565 
01566                 //for no-pilot-death delay
01567                 newent->damage = ent->damage;
01568 
01569                 //no-pilot-death distance
01570                 newent->speed = ent->speed;
01571 
01572                 //for veh transfer all healy stuff
01573                 newent->healingclass = ent->healingclass;
01574                 newent->healingsound = ent->healingsound;
01575                 newent->healingrate = ent->healingrate;
01576                 newent->model2 = ent->model2;//for droidNPC
01577         }
01578         else
01579         {
01580                 newent->client->ps.weapon = WP_NONE;//init for later check in NPC_Begin
01581         }
01582     
01583         VectorCopy(ent->s.origin, newent->s.origin);
01584         VectorCopy(ent->s.origin, newent->client->ps.origin);
01585         VectorCopy(ent->s.origin, newent->r.currentOrigin);
01586         G_SetOrigin(newent, ent->s.origin);//just to be sure!
01587         //NOTE: on vehicles, anything in the .npc file will STOMP data on the NPC that's set by the vehicle
01588         if ( !NPC_ParseParms( ent->NPC_type, newent ) )
01589         {
01590                 Com_Printf ( S_COLOR_RED "ERROR: Couldn't spawn NPC %s\n", ent->NPC_type );
01591                 G_FreeEntity( newent );
01592                 //get rid of the spawner, too, I guess
01593                 G_FreeEntity( ent );
01594                 return NULL;
01595         }
01596 
01597         if ( ent->NPC_type )
01598         {
01599                 if ( !Q_stricmp( ent->NPC_type, "kyle" ) )
01600                 {//FIXME: "player", not Kyle?  Or check NPC_type against player's NPC_type?
01601                         newent->NPC->aiFlags |= NPCAI_MATCHPLAYERWEAPON;
01602                 }
01603                 else if ( !Q_stricmp( ent->NPC_type, "test" ) )
01604                 {
01605                         int     n;
01606                         for ( n = 0; n < 1 ; n++) 
01607                         {
01608                                 if ( g_entities[n].s.eType != ET_NPC && g_entities[n].client) 
01609                                 {
01610                                         VectorCopy(g_entities[n].s.origin, newent->s.origin);
01611                                         newent->client->playerTeam = newent->s.teamowner = g_entities[n].client->playerTeam;
01612                                         break;
01613                                 }
01614                         }
01615                         newent->NPC->defaultBehavior = newent->NPC->behaviorState = BS_WAIT;
01616                         newent->classname = "NPC";
01617         //              newent->r.svFlags |= SVF_NOPUSH;
01618                 }
01619         }
01620 //=====================================================================
01621         //set the info we want
01622         if ( !newent->health )
01623         {
01624                 newent->health = ent->health;
01625         }
01626         newent->script_targetname = ent->NPC_targetname;
01627         newent->targetname = ent->NPC_targetname;
01628         newent->target = ent->NPC_target;//death
01629         newent->target2 = ent->target2;//knocked out death
01630         newent->target3 = ent->target3;//???
01631         newent->target4 = ent->target4;//ffire death
01632         newent->wait = ent->wait;
01633         
01634         for( index = BSET_FIRST; index < NUM_BSETS; index++)
01635         {
01636                 if ( ent->behaviorSet[index] )
01637                 {
01638                         newent->behaviorSet[index] = ent->behaviorSet[index];
01639                 }
01640         }
01641 
01642         newent->classname = "NPC";
01643         newent->NPC_type = ent->NPC_type;
01644         trap_UnlinkEntity(newent);
01645         
01646         VectorCopy(ent->s.angles, newent->s.angles);
01647         VectorCopy(ent->s.angles, newent->r.currentAngles);
01648         VectorCopy(ent->s.angles, newent->client->ps.viewangles);
01649         newent->NPC->desiredYaw =ent->s.angles[YAW];
01650         
01651         trap_LinkEntity(newent);
01652         newent->spawnflags = ent->spawnflags;
01653 
01654         if(ent->paintarget)
01655         {       //safe to point at owner's string since memory is never freed during game
01656                 newent->paintarget = ent->paintarget;
01657         }
01658         if(ent->opentarget)
01659         {
01660                 newent->opentarget = ent->opentarget;
01661         }
01662 
01663 //==New stuff=====================================================================
01664         newent->s.eType = ET_NPC;//ET_PLAYER;
01665         
01666         //FIXME: Call CopyParms
01667         if ( ent->parms )
01668         {
01669                 int parmNum;
01670 
01671                 for ( parmNum = 0; parmNum < MAX_PARMS; parmNum++ )
01672                 {
01673                         if ( ent->parms->parm[parmNum] && ent->parms->parm[parmNum][0] )
01674                         {
01675                                 Q3_SetParm( newent->s.number, parmNum, ent->parms->parm[parmNum] );
01676                         }
01677                 }
01678         }
01679         //FIXME: copy cameraGroup, store mine in message or other string field
01680 
01681         //set origin
01682         newent->s.pos.trType = TR_INTERPOLATE;
01683         newent->s.pos.trTime = level.time;
01684         VectorCopy( newent->r.currentOrigin, newent->s.pos.trBase );
01685         VectorClear( newent->s.pos.trDelta );
01686         newent->s.pos.trDuration = 0;
01687         //set angles
01688         newent->s.apos.trType = TR_INTERPOLATE;
01689         newent->s.apos.trTime = level.time;
01690         //VectorCopy( newent->r.currentOrigin, newent->s.apos.trBase );
01691         //Why was the origin being used as angles? Typo I'm assuming -rww
01692         VectorCopy( newent->s.angles, newent->s.apos.trBase );
01693 
01694         VectorClear( newent->s.apos.trDelta );
01695         newent->s.apos.trDuration = 0;
01696         
01697         newent->NPC->combatPoint = -1;
01698 
01699         newent->flags |= FL_NOTARGET;//So he's ignored until he's fully spawned
01700         newent->s.eFlags |= EF_NODRAW;//So he's ignored until he's fully spawned
01701 
01702         newent->think = NPC_Begin;
01703         newent->nextthink = level.time + FRAMETIME;
01704         NPC_DefaultScriptFlags( newent );
01705 
01706         //copy over team variables, too
01707         newent->s.shouldtarget = ent->s.shouldtarget;
01708         newent->s.teamowner = ent->s.teamowner;
01709         newent->alliedTeam = ent->alliedTeam;
01710         newent->teamnodmg = ent->teamnodmg;
01711         if ( ent->team && ent->team[0] )
01712         {//specified team directly?
01713                 newent->client->sess.sessionTeam = atoi(ent->team);
01714         }
01715         else if ( newent->s.teamowner != TEAM_FREE )
01716         {
01717                 newent->client->sess.sessionTeam = newent->s.teamowner;
01718         }
01719         else if ( newent->alliedTeam != TEAM_FREE )
01720         {
01721                 newent->client->sess.sessionTeam = newent->alliedTeam;
01722         }
01723         else if ( newent->teamnodmg != TEAM_FREE )
01724         {
01725                 newent->client->sess.sessionTeam = newent->teamnodmg;
01726         }
01727         else
01728         {
01729                 newent->client->sess.sessionTeam = TEAM_FREE;
01730         }
01731         newent->client->ps.persistant[PERS_TEAM] = newent->client->sess.sessionTeam;
01732 
01733         trap_LinkEntity (newent);
01734 
01735         if(!ent->use)
01736         {
01737                 if( ent->target )
01738                 {//use any target we're pointed at
01739                         G_UseTargets ( ent, ent );
01740                 }
01741                 if(ent->closetarget)
01742                 {//last guy should fire this target when he dies
01743                         newent->target = ent->closetarget;
01744                 }
01745                 ent->targetname = NULL;
01746                 //why not remove me...?  Because of all the string pointers?  Just do G_NewStrings?
01747                 G_FreeEntity( ent );//bye!
01748         }
01749 
01750 finish:
01751         if ( ent->spawnflags & NSF_DROP_TO_FLOOR )
01752         {
01753                 G_SetOrigin( ent, saveOrg );
01754         }
01755 
01756         return newent;
01757 }
01758 
01759 void NPC_Spawn_Go(gentity_t *ent)
01760 {
01761         NPC_Spawn_Do(ent);
01762 }
01763 
01764 /*
01765 -------------------------
01766 NPC_StasisSpawnEffect
01767 -------------------------
01768 */
01769 /*
01770 void NPC_StasisSpawnEffect( gentity_t *ent )
01771 {
01772         vec3_t          start, end, forward;
01773         qboolean        taper;
01774 
01775         //Floor or wall?
01776         if ( ent->spawnflags & 1 )
01777         {
01778                 AngleVectors( ent->s.angles, forward, NULL, NULL );
01779                 VectorMA( ent->r.currentOrigin,  24, forward, end );
01780                 VectorMA( ent->r.currentOrigin, -20, forward, start );
01781                 
01782                 start[2] += 64;
01783                 
01784                 taper = qtrue;
01785         }
01786         else
01787         {
01788                 VectorCopy( ent->r.currentOrigin, start );
01789                 VectorCopy( start, end );
01790                 end[2] += 48;
01791                 taper = qfalse;
01792         }
01793 
01794         //Add the effect
01795 //      CG_ShimmeryThing_Spawner( start, end, 32, qtrue, 1000 );
01796 }
01797 */
01798 /*
01799 -------------------------
01800 NPC_ShySpawn
01801 -------------------------
01802 */
01803 
01804 #define SHY_THINK_TIME                  1000
01805 #define SHY_SPAWN_DISTANCE              128
01806 #define SHY_SPAWN_DISTANCE_SQR  ( SHY_SPAWN_DISTANCE * SHY_SPAWN_DISTANCE )
01807 
01808 void NPC_ShySpawn( gentity_t *ent )
01809 {
01810         ent->nextthink = level.time + SHY_THINK_TIME;
01811         ent->think = NPC_ShySpawn;
01812 
01813         //rwwFIXMEFIXME: Care about other clients not just 0?
01814         if ( DistanceSquared( g_entities[0].r.currentOrigin, ent->r.currentOrigin ) <= SHY_SPAWN_DISTANCE_SQR )
01815                 return;
01816 
01817         if ( (InFOV( ent, &g_entities[0], 80, 64 )) ) // FIXME: hardcoded fov
01818                 if ( (NPC_ClearLOS2( &g_entities[0], ent->r.currentOrigin )) )
01819                         return;
01820 
01821         ent->think = 0;
01822         ent->nextthink = 0;
01823 
01824         NPC_Spawn_Go( ent );
01825 }
01826 
01827 /*
01828 -------------------------
01829 NPC_Spawn
01830 -------------------------
01831 */
01832 
01833 void NPC_Spawn ( gentity_t *ent, gentity_t *other, gentity_t *activator )
01834 {
01835         //delay before spawning NPC
01836         if( ent->delay )
01837         {
01838 /*              //Stasis does an extra step
01839                 if ( Q_stricmp( ent->classname, "NPC_Stasis" ) == 0 )
01840                 {
01841                         if ( NPC_StasisSpawn_Go( ent ) == qfalse )
01842                                 return;
01843                 }
01844 */
01845                 if ( ent->spawnflags & 2048 )  // SHY
01846                 {
01847                         ent->think = NPC_ShySpawn;
01848                 }
01849                 else
01850                 {
01851                         ent->think = NPC_Spawn_Go;
01852                 }
01853 
01854                 ent->nextthink = level.time + ent->delay;
01855         }
01856         else
01857         {
01858                 if ( ent->spawnflags & 2048 )  // SHY
01859                 {
01860                         NPC_ShySpawn( ent );
01861                 }
01862                 else
01863                 {
01864                         NPC_Spawn_Do( ent );
01865                 }
01866         }
01867 }
01868 
01869 /*QUAKED NPC_spawner (1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
01870 
01871 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
01872 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
01873 NOTSOLID - Starts not solid
01874 STARTINSOLID - Don't try to fix if spawn in solid
01875 SHY - Spawner is shy
01876 
01877 NPC_type - name of NPC (in npcs.cfg) to spawn in
01878 
01879 targetname - name this NPC goes by for targetting
01880 target - NPC will fire this when it spawns it's last NPC (should this be when the last NPC it spawned dies?)
01881 target2 - Fired by stasis spawners when they try to spawn while their spawner model is broken
01882 target3 - Fired by spawner if they try to spawn and are blocked and have a wait < 0 (removes them)
01883 
01884 If targeted, will only spawn a NPC when triggered
01885 count - how many NPCs to spawn (only if targetted) default = 1
01886 delay - how long to wait to spawn after used
01887 wait - if trying to spawn and blocked, how many seconds to wait before trying again (default = 0.5, < 0 = never try again and fire target2)
01888 
01889 NPC_targetname - NPC's targetname AND script_targetname
01890 NPC_target - NPC's target to fire when killed
01891 NPC_target2 - NPC's target to fire when knocked out
01892 NPC_target4 - NPC's target to fire when killed by friendly fire
01893 NPC_type - type of NPC ("Borg" (default), "Xian", etc)
01894 health - starting health (default = 100)
01895 
01896 spawnscript - default script to run once spawned (none by default)
01897 usescript - default script to run when used (none by default)
01898 awakescript - default script to run once awoken (none by default)
01899 angerscript - default script to run once angered (none by default)
01900 painscript - default script to run when hit (none by default)
01901 fleescript - default script to run when hit and below 50% health (none by default)
01902 deathscript - default script to run when killed (none by default)
01903 These strings can be used to activate behaviors instead of scripts - these are checked
01904 first and so no scripts should be names with these names:
01905     default - 0: whatever
01906         idle - 1: Stand around, do abolutely nothing
01907         roam - 2: Roam around, collect stuff
01908         walk - 3: Crouch-Walk toward their goals
01909         run - 4: Run toward their goals
01910         standshoot - 5: Stay in one spot and shoot- duck when neccesary
01911         standguard - 6: Wait around for an enemy
01912         patrol - 7: Follow a path, looking for enemies
01913         huntkill - 8: Track down enemies and kill them
01914         evade - 9: Run from enemies
01915         evadeshoot - 10: Run from enemies, shoot them if they hit you
01916         runshoot - 11: Run to your goal and shoot enemy when possible
01917         defend - 12: Defend an entity or spot?
01918         snipe - 13: Stay hidden, shoot enemy only when have perfect shot and back turned
01919         combat - 14: Attack, evade, use cover, move about, etc.  Full combat AI - id NPC code
01920         medic - 15: Go for lowest health buddy, hide and heal him.
01921         takecover - 16: Find nearest cover from enemies
01922         getammo - 17: Go get some ammo
01923         advancefight - 18: Go somewhere and fight along the way
01924         face - 19: turn until facing desired angles
01925         wait - 20: do nothing
01926         formation - 21: Maintain a formation
01927         crouch - 22: Crouch-walk toward their goals
01928 
01929 delay - after spawned or triggered, how many seconds to wait to spawn the NPC
01930 
01931 showhealth - set to 1 to show health bar on this entity when crosshair is over it
01932 
01933 teamowner - crosshair shows green for this team, red for opposite team
01934         0 - none
01935         1 - red
01936         2 - blue
01937 
01938 teamuser - only this team can use this NPC
01939         0 - none
01940         1 - red
01941         2 - blue
01942 
01943 teamnodmg - team that NPC does not take damage from (turrets and other auto-defenses that have "alliedTeam" set to this team won't target this NPC)
01944         0 - none
01945         1 - red
01946         2 - blue
01947 
01948 "noBasicSounds" - set to 1 to prevent loading and usage of basic sounds (pain, death, etc)
01949 "noCombatSounds" - set to 1 to prevent loading and usage of combat sounds (anger, victory, etc.)
01950 "noExtraSounds" - set to 1 to prevent loading and usage of "extra" sounds (chasing the enemy - detecting them, flanking them... also jedi combat sounds)
01951 */
01952 //void NPC_PrecacheModels ( char *NPCName );
01953 extern void NPC_PrecacheAnimationCFG( const char *NPC_type );
01954 void NPC_Precache ( gentity_t *spawner );
01955 void NPC_PrecacheType( char *NPC_type )
01956 {
01957         gentity_t *fakespawner = G_Spawn();
01958         if ( fakespawner )
01959         {
01960                 fakespawner->NPC_type = NPC_type;
01961                 NPC_Precache( fakespawner );
01962                 //NOTE: does the spawner have to stay around to send any precached info to the clients...?
01963                 G_FreeEntity( fakespawner );
01964         }
01965 }
01966 
01967 void SP_NPC_spawner( gentity_t *self)
01968 {
01969         int t;
01970 
01971         if (!g_allowNPC.integer)
01972         {
01973                 self->think = G_FreeEntity;
01974                 self->nextthink = level.time;
01975                 return;
01976         }
01977         if ( !self->fullName || !self->fullName[0] )
01978         {
01979                 //FIXME: make an index into an external string table for localization
01980                 self->fullName = "Humanoid Lifeform";
01981         }
01982 
01983         //register/precache the models needed for this NPC, not anymore
01984         //self->classname = "NPC_spawner";
01985 
01986         if(!self->count)
01987         {
01988                 self->count = 1;
01989         }
01990 
01991         {//Stop loading of certain extra sounds
01992                 static  int     garbage;
01993 
01994                 if ( G_SpawnInt( "noBasicSounds", "0", &garbage ) )
01995                 {
01996                         self->r.svFlags |= SVF_NO_BASIC_SOUNDS;
01997                 }
01998                 if ( G_SpawnInt( "noCombatSounds", "0", &garbage ) )
01999                 {
02000                         self->r.svFlags |= SVF_NO_COMBAT_SOUNDS;
02001                 }
02002                 if ( G_SpawnInt( "noExtraSounds", "0", &garbage ) )
02003                 {
02004                         self->r.svFlags |= SVF_NO_EXTRA_SOUNDS;
02005                 }
02006         }
02007 
02008         if ( !self->wait )
02009         {
02010                 self->wait = 500;
02011         }
02012         else
02013         {
02014                 self->wait *= 1000;//1 = 1 msec, 1000 = 1 sec
02015         }
02016 
02017         self->delay *= 1000;//1 = 1 msec, 1000 = 1 sec
02018 
02019         G_SpawnInt( "showhealth", "0", &t );
02020         if (t)
02021         {
02022                 self->s.shouldtarget = qtrue;
02023         }
02024         /*
02025         if ( self->delay > 0 )
02026         {
02027                 self->r.svFlags |= SVF_NPC_PRECACHE;
02028         }
02029         */
02030         //rwwFIXMEFIXME: support for this flag?
02031 
02032         //We have to load the animation.cfg now because spawnscripts are going to want to set anims and we need to know their length and if they're valid
02033         NPC_PrecacheAnimationCFG( self->NPC_type );
02034 
02035         //rww - can't cheat and do this on the client like in SP, so I'm doing this.
02036         NPC_Precache(self);
02037 
02038         if ( self->targetname )
02039         {//Wait for triggering
02040                 self->use = NPC_Spawn;
02041         //      self->r.svFlags |= SVF_NPC_PRECACHE;//FIXME: precache my weapons somehow?
02042 
02043                 //NPC_PrecacheModels( self->NPC_type );
02044         }
02045         else
02046         {
02047                 //NOTE: auto-spawners never check for shy spawning
02048                 //if ( spawning )
02049                 if (1) //just gonna always do this I suppose.
02050                 {//in entity spawn stage - map starting up
02051                         self->think = NPC_Spawn_Go;
02052                         self->nextthink = level.time + START_TIME_REMOVE_ENTS + 50;
02053                 }
02054                 else
02055                 {//else spawn right now
02056                         NPC_Spawn( self, self, self );
02057                 }
02058         }
02059 
02060         //FIXME: store cameraGroup somewhere else and apply to spawned NPCs' cameraGroup
02061         //Or just don't include NPC_spawners in cameraGroupings
02062 }
02063 
02064 extern void G_VehicleSpawn( gentity_t *self );
02065 /*QUAKED NPC_Vehicle (1 0 0) (-16 -16 -24) (16 16 32) NO_PILOT_DIE SUSPENDED x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
02066 NO_PILOT_DIE - die after certain amount of time of not having a pilot
02067 SUSPENDED - Fighters: Don't drop until someone gets in it (this only works as long as no-nw has *ever* ridden the vehicle, to simulate ships that are suspended-docked) - note: ships inside trigger_spaces do not drop when unoccupied
02068 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02069 NOTSOLID - Starts not solid
02070 STARTINSOLID - Don't try to fix if spawn in solid
02071 SHY - Spawner is shy
02072 
02073 set NPC_type to vehicle name in vehicles.dat
02074 
02075 "dropTime" use with SUSPENDED - if set, the vehicle will drop straight down for this number of seconds before flying forward
02076 "dmg" use with NO_PILOT_DIE - delay in milliseconds for ship to explode if no pilot (default 10000)
02077 "speed" use with NO_PILOT_DIE - distance for pilot to get away from ship after dismounting before it starts counting down the death timer
02078 "model2" - if the vehicle can have a droid (has "*droidunit" tag), this NPC will be spawned and placed there - note: game will automatically use the one specified in the .veh file (if any) or, absent that, it will use an R2D2 or R5D2 NPC)
02079 
02080 showhealth - set to 1 to show health bar on this entity when crosshair is over it
02081 
02082 teamowner - crosshair shows green for this team, red for opposite team
02083         0 - none
02084         1 - red
02085         2 - blue
02086 
02087 teamuser - only this team can use this NPC
02088         0 - none
02089         1 - red
02090         2 - blue
02091 
02092 teamnodmg - team that NPC does not take damage from (turrets and other auto-defenses that have "alliedTeam" set to this team won't target this NPC)
02093         0 - none
02094         1 - red
02095         2 - blue
02096 */
02097 qboolean NPC_VehiclePrecache( gentity_t *spawner )
02098 {
02099         char *droidNPCType = NULL;
02100         //This will precache the vehicle
02101         vehicleInfo_t *pVehInfo;
02102         int iVehIndex = BG_VehicleGetIndex( spawner->NPC_type );
02103         if ( iVehIndex == VEHICLE_NONE )
02104         {//fixme: error msg?
02105                 return qfalse;
02106         }
02107 
02108         G_ModelIndex(va("$%s", spawner->NPC_type)); //make sure the thing is frickin precached
02109         //now cache his model/skin/anim config
02110         pVehInfo = &g_vehicleInfo[iVehIndex];
02111         if (pVehInfo->model && pVehInfo->model[0])
02112         {
02113                 void *tempG2 = NULL;
02114                 int skin = 0;
02115                 if (pVehInfo->skin && pVehInfo->skin[0])
02116                 {
02117                         skin = trap_R_RegisterSkin(va("models/players/%s/model_%s.skin", pVehInfo->model, pVehInfo->skin));
02118                 }
02119                 trap_G2API_InitGhoul2Model(&tempG2, va("models/players/%s/model.glm", pVehInfo->model), 0, skin, 0, 0, 0);
02120                 if (tempG2)
02121                 { //now, cache the anim config.
02122                         char GLAName[1024];
02123 
02124                         GLAName[0] = 0;
02125                         trap_G2API_GetGLAName(tempG2, 0, GLAName);
02126 
02127                         if (GLAName[0])
02128                         {
02129                                 char *slash = Q_strrchr( GLAName, '/' );
02130                                 if ( slash )
02131                                 {
02132                                         strcpy(slash, "/animation.cfg");
02133 
02134                                         BG_ParseAnimationFile(GLAName, NULL, qfalse);
02135                                 }
02136                         }
02137                         trap_G2API_CleanGhoul2Models(&tempG2);
02138                 }
02139         }
02140 
02141         //also precache the droid NPC if there is one
02142         if ( spawner->model2 
02143                 && spawner->model2[0] )
02144         {
02145                 droidNPCType = spawner->model2;
02146         }
02147         else if ( g_vehicleInfo[iVehIndex].droidNPC
02148                 && g_vehicleInfo[iVehIndex].droidNPC[0] )
02149         {
02150                 droidNPCType = g_vehicleInfo[iVehIndex].droidNPC;
02151         }
02152 
02153         if ( droidNPCType )
02154         {
02155                 if ( Q_stricmp( "random", droidNPCType ) == 0
02156                         || Q_stricmp( "default", droidNPCType ) == 0 )
02157                 {//precache both r2 and r5, as defaults
02158                         NPC_PrecacheType( "r2d2" );
02159                         NPC_PrecacheType( "r5d2" );
02160                 }
02161                 else
02162                 {
02163                         NPC_PrecacheType( droidNPCType );
02164                 }
02165         }
02166         return qtrue;
02167 }
02168 
02169 void NPC_VehicleSpawnUse( gentity_t *self, gentity_t *other, gentity_t *activator )
02170 {
02171         if ( self->delay )
02172         {
02173                 self->think = G_VehicleSpawn;
02174                 self->nextthink = level.time + self->delay;
02175         }
02176         else
02177         {
02178                 G_VehicleSpawn( self );
02179         }
02180 }
02181 
02182 void SP_NPC_Vehicle( gentity_t *self)
02183 {
02184         float dropTime;
02185         int             t;
02186         if ( !self->NPC_type )
02187         {
02188                 self->NPC_type = "swoop";
02189         }
02190 
02191         if ( !self->classname )
02192         {
02193                 self->classname = "NPC_Vehicle";
02194         }
02195 
02196         if ( !self->wait )
02197         {
02198                 self->wait = 500;
02199         }
02200         else
02201         {
02202                 self->wait *= 1000;//1 = 1 msec, 1000 = 1 sec
02203         }
02204         self->delay *= 1000;//1 = 1 msec, 1000 = 1 sec
02205 
02206         G_SetOrigin( self, self->s.origin );
02207         G_SetAngles( self, self->s.angles );
02208         G_SpawnFloat( "dropTime", "0", &dropTime );
02209         if ( dropTime )
02210         {
02211                 self->fly_sound_debounce_time = ceil(dropTime*1000.0);
02212         }
02213         
02214         G_SpawnInt( "showhealth", "0", &t );
02215         if (t)
02216         {
02217                 self->s.shouldtarget = qtrue;
02218         }
02219         //FIXME: PRECACHE!!!
02220 
02221         if ( self->targetname )
02222         {
02223                 if ( !NPC_VehiclePrecache( self ) )
02224                 {//FIXME: err msg?
02225                         G_FreeEntity( self );
02226                         return;
02227                 }
02228                 self->use = NPC_VehicleSpawnUse;
02229         }
02230         else
02231         {
02232                 if ( self->delay )
02233                 {
02234                         if ( !NPC_VehiclePrecache( self ) )
02235                         {//FIXME: err msg?
02236                                 G_FreeEntity( self );
02237                                 return;
02238                         }
02239                         self->think = G_VehicleSpawn;
02240                         self->nextthink = level.time + self->delay;
02241                 }
02242                 else
02243                 {
02244                         G_VehicleSpawn( self );
02245                 }
02246         }
02247 }
02248 
02249 //Characters
02250 
02251 //STAR WARS NPCs============================================================================
02252 /*QUAKED NPC_spawner (1 0 0) (-16 -16 -24) (16 16 32) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
02253 
02254 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02255 NOTSOLID - Starts not solid
02256 STARTINSOLID - Don't try to fix if spawn in solid
02257 SHY - Spawner is shy
02258 
02259 targetname - name this NPC goes by for targetting
02260 target - NPC will fire this when it spawns it's last NPC (should this be when the last NPC it spawned dies?)
02261 
02262 If targeted, will only spawn a NPC when triggered
02263 count - how many NPCs to spawn (only if targetted) default = 1
02264 
02265 NPC_type - the name of the NPC (from NPCs.cfg or a from .npc file)
02266 
02267 NPC_targetname - NPC's targetname AND script_targetname
02268 NPC_target - NPC's target to fire when killed
02269 health - starting health (default = 100)
02270 playerTeam - Who not to shoot! (default is TEAM_STARFLEET)
02271         TEAM_FREE (none) = 0
02272         TEAM_RED = 1
02273         TEAM_BLUE = 2
02274         TEAM_GOLD = 3
02275         TEAM_GREEN = 4
02276         TEAM_STARFLEET = 5
02277         TEAM_BORG = 6
02278         TEAM_SCAVENGERS = 7
02279         TEAM_STASIS = 8
02280         TEAM_NPCS = 9
02281         TEAM_HARVESTER, = 10
02282         TEAM_FORGE = 11
02283 enemyTeam - Who to shoot (all but own if not set)
02284 
02285 spawnscript - default script to run once spawned (none by default)
02286 usescript - default script to run when used (none by default)
02287 awakescript - default script to run once awoken (none by default)
02288 angerscript - default script to run once angered (none by default)
02289 painscript - default script to run when hit (none by default)
02290 fleescript - default script to run when hit and below 50% health (none by default)
02291 deathscript - default script to run when killed (none by default)
02292 
02293 These strings can be used to activate behaviors instead of scripts - these are checked
02294 first and so no scripts should be names with these names:
02295     default - 0: whatever
02296         idle - 1: Stand around, do abolutely nothing
02297         roam - 2: Roam around, collect stuff
02298         walk - 3: Crouch-Walk toward their goals
02299         run - 4: Run toward their goals
02300         standshoot - 5: Stay in one spot and shoot- duck when neccesary
02301         standguard - 6: Wait around for an enemy
02302         patrol - 7: Follow a path, looking for enemies
02303         huntkill - 8: Track down enemies and kill them
02304         evade - 9: Run from enemies
02305         evadeshoot - 10: Run from enemies, shoot them if they hit you
02306         runshoot - 11: Run to your goal and shoot enemy when possible
02307         defend - 12: Defend an entity or spot?
02308         snipe - 13: Stay hidden, shoot enemy only when have perfect shot and back turned
02309         combat - 14: Attack, evade, use cover, move about, etc.  Full combat AI - id NPC code
02310         medic - 15: Go for lowest health buddy, hide and heal him.
02311         takecover - 16: Find nearest cover from enemies
02312         getammo - 17: Go get some ammo
02313         advancefight - 18: Go somewhere and fight along the way
02314         face - 19: turn until facing desired angles
02315         wait - 20: do nothing
02316         formation - 21: Maintain a formation
02317         crouch - 22: Crouch-walk toward their goals
02318 
02319 delay - after spawned or triggered, how many seconds to wait to spawn the NPC
02320 */
02321 
02322 //=============================================================================================
02323 //CHARACTERS
02324 //=============================================================================================
02325 
02326 /*QUAKED NPC_Kyle (1 0 0) (-16 -16 -24) (16 16 32) x RIFLEMAN PHASER TRICORDER DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
02327 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02328 NOTSOLID - Starts not solid
02329 STARTINSOLID - Don't try to fix if spawn in solid
02330 SHY - Spawner is shy
02331 */
02332 void SP_NPC_Kyle( gentity_t *self)
02333 {
02334         self->NPC_type = "Kyle";
02335 
02336         WP_SetSaberModel( NULL, CLASS_KYLE );
02337 
02338         SP_NPC_spawner( self );
02339 }
02340 
02341 /*QUAKED NPC_Lando(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
02342 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
02343 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02344 NOTSOLID - Starts not solid
02345 STARTINSOLID - Don't try to fix if spawn in solid
02346 SHY - Spawner is shy
02347 */
02348 void SP_NPC_Lando( gentity_t *self)
02349 {
02350         self->NPC_type = "Lando";
02351 
02352         SP_NPC_spawner( self );
02353 }
02354 
02355 /*QUAKED NPC_Jan(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
02356 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
02357 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02358 NOTSOLID - Starts not solid
02359 STARTINSOLID - Don't try to fix if spawn in solid
02360 SHY - Spawner is shy
02361 */
02362 void SP_NPC_Jan( gentity_t *self)
02363 {
02364         self->NPC_type = "Jan";
02365 
02366         SP_NPC_spawner( self );
02367 }
02368 
02369 /*QUAKED NPC_Luke(1 0 0) (-16 -16 -24) (16 16 40) x x x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
02370 CEILING - Sticks to the ceiling until he sees an enemy or takes pain
02371 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02372 NOTSOLID - Starts not solid
02373 STARTINSOLID - Don't try to fix if spawn in solid
02374 SHY - Spawner is shy
02375 */
02376 void SP_NPC_Luke( gentity_t *self)
02377 {
02378         self->NPC_type = "Luke";
02379 
02380         WP_SetSaberModel( NULL, CLASS_LUKE );
02381 
02382         SP_NPC_spawner( self );
02383 }
02384 
02385 /*QUAKED NPC_MonMothma(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
02386 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
02387 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02388 NOTSOLID - Starts not solid
02389 STARTINSOLID - Don't try to fix if spawn in solid
02390 SHY - Spawner is shy
02391 */
02392 void SP_NPC_MonMothma( gentity_t *self)
02393 {
02394         self->NPC_type = "MonMothma";
02395 
02396         SP_NPC_spawner( self );
02397 }
02398 
02399 /*QUAKED NPC_Tavion (1 0 0) (-16 -16 -24) (16 16 32) x x x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
02400 CEILING - Sticks to the ceiling until he sees an enemy or takes pain
02401 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02402 NOTSOLID - Starts not solid
02403 STARTINSOLID - Don't try to fix if spawn in solid
02404 SHY - Spawner is shy
02405 */
02406 void SP_NPC_Tavion( gentity_t *self)
02407 {
02408         self->NPC_type = "Tavion";
02409 
02410         WP_SetSaberModel( NULL, CLASS_TAVION );
02411 
02412         SP_NPC_spawner( self );
02413 }
02414 
02415 /*QUAKED NPC_Tavion_New (1 0 0) (-16 -16 -24) (16 16 32) SCEPTER SITH_SWORD x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
02416 Has a red lightsaber and force powers, uses her saber style from JK2
02417 
02418 SCEPTER - Has a red lightsaber and force powers, Ragnos' Scepter in left hand, uses dual saber style and occasionally attacks with Scepter
02419 SITH_SWORD - Has Ragnos' Sith Sword in right hand and force powers, uses strong style
02420 CEILING - Sticks to the ceiling until he sees an enemy or takes pain
02421 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02422 NOTSOLID - Starts not solid
02423 STARTINSOLID - Don't try to fix if spawn in solid
02424 SHY - Spawner is shy
02425 */
02426 void SP_NPC_Tavion_New( gentity_t *self)
02427 {
02428         if ( (self->spawnflags&1) )
02429         {
02430                 self->NPC_type = "tavion_scepter";
02431         }
02432         else if ( (self->spawnflags&2) )
02433         {
02434                 self->NPC_type = "tavion_sith_sword";
02435         }
02436         else
02437         {
02438                 self->NPC_type = "tavion_new";
02439         }
02440 
02441         SP_NPC_spawner( self );
02442 }
02443 
02444 /*QUAKED NPC_Alora (1 0 0) (-16 -16 -24) (16 16 32) DUAL x x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
02445 Lightsaber and level 2 force powers, 300 health
02446 
02447 DUAL - Dual sabers and level 3 force powers, 500 health
02448 CEILING - Sticks to the ceiling until he sees an enemy or takes pain
02449 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02450 NOTSOLID - Starts not solid
02451 STARTINSOLID - Don't try to fix if spawn in solid
02452 SHY - Spawner is shy
02453 */
02454 void SP_NPC_Alora( gentity_t *self)
02455 {
02456         if ( (self->spawnflags&1) )
02457         {
02458                 self->NPC_type = "alora_dual";
02459         }
02460         else
02461         {
02462                 self->NPC_type = "alora";
02463         }
02464 
02465         SP_NPC_spawner( self );
02466 }
02467 
02468 /*QUAKED NPC_Reborn_New(1 0 0) (-16 -16 -24) (16 16 40) DUAL STAFF WEAK x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
02469 
02470 Reborn is an excellent lightsaber fighter, acrobatic and uses force powers.  Full-length red saber, 200 health.
02471 
02472 DUAL - Use 2 shorter sabers
02473 STAFF - Uses a saber staff
02474 WEAK - Is a bit less tough
02475 CEILING - Sticks to the ceiling until he sees an enemy or takes pain
02476 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02477 NOTSOLID - Starts not solid
02478 STARTINSOLID - Don't try to fix if spawn in solid
02479 SHY - Spawner is shy
02480 */
02481 void SP_NPC_Reborn_New( gentity_t *self)
02482 {
02483         if ( !self->NPC_type )
02484         {
02485                 if ( (self->spawnflags&4) )
02486                 {//weaker guys
02487                         if ( (self->spawnflags&1) )
02488                         {
02489                                 self->NPC_type = "reborn_dual2";
02490                         }
02491                         else if ( (self->spawnflags&2) )
02492                         {
02493                                 self->NPC_type = "reborn_staff2";
02494                         }
02495                         else
02496                         {
02497                                 self->NPC_type = "reborn_new2";
02498                         }
02499                 }
02500                 else
02501                 {
02502                         if ( (self->spawnflags&1) )
02503                         {
02504                                 self->NPC_type = "reborn_dual";
02505                         }
02506                         else if ( (self->spawnflags&2) )
02507                         {
02508                                 self->NPC_type = "reborn_staff";
02509                         }
02510                         else
02511                         {
02512                                 self->NPC_type = "reborn_new";
02513                         }
02514                 }
02515         }
02516         
02517         SP_NPC_spawner( self );
02518 }
02519 
02520 /*QUAKED NPC_Cultist_Saber(1 0 0) (-16 -16 -24) (16 16 40) MED STRONG ALL THROW CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
02521 Uses a saber and no force powers.  100 health.
02522 
02523 default fencer uses fast style - weak, but can attack rapidly.  Good defense.
02524 
02525 MED - Uses medium style - average speed and attack strength, average defense.
02526 STRONG - Uses strong style, slower than others, but can do a lot of damage with one blow.  Weak defense.
02527 ALL - Knows all 3 styles, switches between them, good defense.
02528 THROW - can throw their saber (level 2) - reduces their defense some (can use this spawnflag alone or in combination with any *one* of the previous 3 spawnflags)
02529 
02530 CEILING - Sticks to the ceiling until he sees an enemy or takes pain
02531 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02532 NOTSOLID - Starts not solid
02533 STARTINSOLID - Don't try to fix if spawn in solid
02534 SHY - Spawner is shy
02535 */
02536 void SP_NPC_Cultist_Saber( gentity_t *self)
02537 {
02538         if ( !self->NPC_type )
02539         {
02540                 if ( (self->spawnflags&1) )
02541                 {
02542                         if ( (self->spawnflags&8) )
02543                         {
02544                                 self->NPC_type = "cultist_saber_med_throw";
02545                         }
02546                         else
02547                         {
02548                                 self->NPC_type = "cultist_saber_med";
02549                         }
02550                 }
02551                 else if ( (self->spawnflags&2) )
02552                 {
02553                         if ( (self->spawnflags&8) )
02554                         {
02555                                 self->NPC_type = "cultist_saber_strong_throw";
02556                         }
02557                         else
02558                         {
02559                                 self->NPC_type = "cultist_saber_strong";
02560                         }
02561                 }
02562                 else if ( (self->spawnflags&2) )
02563                 {
02564                         if ( (self->spawnflags&8) )
02565                         {
02566                                 self->NPC_type = "cultist_saber_all_throw";
02567                         }
02568                         else
02569                         {
02570                                 self->NPC_type = "cultist_saber_all";
02571                         }
02572                 }
02573                 else
02574                 {
02575                         if ( (self->spawnflags&8) )
02576                         {
02577                                 self->NPC_type = "cultist_saber_throw";
02578                         }
02579                         else
02580                         {
02581                                 self->NPC_type = "cultist_saber";
02582                         }
02583                 }
02584         }
02585         
02586         SP_NPC_spawner( self );
02587 }
02588 
02589 /*QUAKED NPC_Cultist_Saber_Powers(1 0 0) (-16 -16 -24) (16 16 40) MED STRONG ALL THROW CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
02590 Uses a saber and has a couple low-level powers.  150 health.
02591 
02592 default fencer uses fast style - weak, but can attack rapidly.  Good defense.
02593 
02594 MED - Uses medium style - average speed and attack strength, average defense.
02595 STRONG - Uses strong style, slower than others, but can do a lot of damage with one blow.  Weak defense.
02596 ALL - Knows all 3 styles, switches between them, good defense.
02597 THROW - can throw their saber (level 2) - reduces their defense some (can use this spawnflag alone or in combination with any *one* of the previous 3 spawnflags)
02598 
02599 CEILING - Sticks to the ceiling until he sees an enemy or takes pain
02600 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02601 NOTSOLID - Starts not solid
02602 STARTINSOLID - Don't try to fix if spawn in solid
02603 SHY - Spawner is shy
02604 */
02605 void SP_NPC_Cultist_Saber_Powers( gentity_t *self)
02606 {
02607         if ( !self->NPC_type )
02608         {
02609                 if ( (self->spawnflags&1) )
02610                 {
02611                         if ( (self->spawnflags&8) )
02612                         {
02613                                 self->NPC_type = "cultist_saber_med_throw2";
02614                         }
02615                         else
02616                         {
02617                                 self->NPC_type = "cultist_saber_med2";
02618                         }
02619                 }
02620                 else if ( (self->spawnflags&2) )
02621                 {
02622                         if ( (self->spawnflags&8) )
02623                         {
02624                                 self->NPC_type = "cultist_saber_strong_throw2";
02625                         }
02626                         else
02627                         {
02628                                 self->NPC_type = "cultist_saber_strong2";
02629                         }
02630                 }
02631                 else if ( (self->spawnflags&2) )
02632                 {
02633                         if ( (self->spawnflags&8) )
02634                         {
02635                                 self->NPC_type = "cultist_saber_all_throw2";
02636                         }
02637                         else
02638                         {
02639                                 self->NPC_type = "cultist_saber_all2";
02640                         }
02641                 }
02642                 else
02643                 {
02644                         if ( (self->spawnflags&8) )
02645                         {
02646                                 self->NPC_type = "cultist_saber_throw";
02647                         }
02648                         else
02649                         {
02650                                 self->NPC_type = "cultist_saber2";
02651                         }
02652                 }
02653         }
02654         
02655         SP_NPC_spawner( self );
02656 }
02657 
02658 /*QUAKED NPC_Cultist(1 0 0) (-16 -16 -24) (16 16 40) SABER GRIP LIGHTNING DRAIN CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
02659 
02660 Cultist uses a blaster and force powers.  40 health.
02661 
02662 SABER - Uses a saber and no force powers
02663 GRIP - Uses no weapon and grip, push and pull
02664 LIGHTNING - Uses no weapon and lightning and push
02665 DRAIN - Uses no weapons and drain and push
02666 
02667 CEILING - Sticks to the ceiling until he sees an enemy or takes pain
02668 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02669 NOTSOLID - Starts not solid
02670 STARTINSOLID - Don't try to fix if spawn in solid
02671 SHY - Spawner is shy
02672 */
02673 void SP_NPC_Cultist( gentity_t *self)
02674 {
02675         if ( !self->NPC_type )
02676         {
02677                 if ( (self->spawnflags&1) )
02678                 {
02679                         self->NPC_type = NULL;
02680                         self->spawnflags = 0;//fast, no throw
02681                         switch ( Q_irand( 0, 2 ) )
02682                         {
02683                         case 0://medium
02684                                 self->spawnflags |= 1;
02685                                 break;
02686                         case 1://strong
02687                                 self->spawnflags |= 2;
02688                                 break;
02689                         case 2://all
02690                                 self->spawnflags |= 4;
02691                                 break;
02692                         }
02693                         if ( Q_irand( 0, 1 ) )
02694                         {//throw
02695                                 self->spawnflags |= 8;
02696                         }
02697                         SP_NPC_Cultist_Saber( self );
02698                         return;
02699                 }
02700                 else if ( (self->spawnflags&2) )
02701                 {
02702                         self->NPC_type = "cultist_grip";
02703                 }
02704                 else if ( (self->spawnflags&4) )
02705                 {
02706                         self->NPC_type = "cultist_lightning";
02707                 }
02708                 else if ( (self->spawnflags&8) )
02709                 {
02710                         self->NPC_type = "cultist_drain";
02711                 }
02712                 else
02713                 {
02714                         self->NPC_type = "cultist";
02715                 }
02716         }
02717         
02718         SP_NPC_spawner( self );
02719 }
02720 
02721 /*QUAKED NPC_Cultist_Commando(1 0 0) (-16 -16 -24) (16 16 40) x x x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
02722 
02723 Cultist uses dual blaster pistols and force powers.  40 health.
02724 
02725 CEILING - Sticks to the ceiling until he sees an enemy or takes pain
02726 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02727 NOTSOLID - Starts not solid
02728 STARTINSOLID - Don't try to fix if spawn in solid
02729 SHY - Spawner is shy
02730 */
02731 void SP_NPC_Cultist_Commando( gentity_t *self)
02732 {
02733         if ( !self->NPC_type )
02734         {
02735                 self->NPC_type = "cultistcommando";
02736         }
02737         SP_NPC_spawner( self );
02738 }
02739 /*QUAKED NPC_Cultist_Destroyer(1 0 0) (-16 -16 -24) (16 16 40) x x x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
02740 
02741 Cultist has no weapons, runs up to you chanting & building up a Force Destruction blast - when gets to you, screams & explodes
02742 
02743 CEILING - Sticks to the ceiling until he sees an enemy or takes pain
02744 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02745 NOTSOLID - Starts not solid
02746 STARTINSOLID - Don't try to fix if spawn in solid
02747 SHY - Spawner is shy
02748 */
02749 void SP_NPC_Cultist_Destroyer( gentity_t *self)
02750 {
02751         self->NPC_type = "cultist";//"cultist_explode";
02752         SP_NPC_spawner( self );
02753 }
02754 
02755 /*QUAKED NPC_Reelo(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
02756 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
02757 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02758 NOTSOLID - Starts not solid
02759 STARTINSOLID - Don't try to fix if spawn in solid
02760 SHY - Spawner is shy
02761 */
02762 void SP_NPC_Reelo( gentity_t *self)
02763 {
02764         self->NPC_type = "Reelo";
02765 
02766         SP_NPC_spawner( self );
02767 }
02768 
02769 /*QUAKED NPC_Galak(1 0 0) (-16 -16 -24) (16 16 40) MECH x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
02770 MECH - will be the armored Galak
02771 
02772 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
02773 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02774 NOTSOLID - Starts not solid
02775 STARTINSOLID - Don't try to fix if spawn in solid
02776 SHY - Spawner is shy
02777 */
02778 void SP_NPC_Galak( gentity_t *self)
02779 {
02780         if ( self->spawnflags & 1 )
02781         {
02782                 self->NPC_type = "Galak_Mech";
02783                 NPC_GalakMech_Precache();
02784         }
02785         else
02786         {
02787                 self->NPC_type = "Galak";
02788         }
02789 
02790         SP_NPC_spawner( self );
02791 }
02792 
02793 /*QUAKED NPC_Desann(1 0 0) (-16 -16 -24) (16 16 40) x x x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
02794 CEILING - Sticks to the ceiling until he sees an enemy or takes pain
02795 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02796 NOTSOLID - Starts not solid
02797 STARTINSOLID - Don't try to fix if spawn in solid
02798 SHY - Spawner is shy
02799 */
02800 void SP_NPC_Desann( gentity_t *self)
02801 {
02802         self->NPC_type = "Desann";
02803 
02804         WP_SetSaberModel( NULL, CLASS_DESANN );
02805 
02806         SP_NPC_spawner( self );
02807 }
02808 
02809 /*QUAKED NPC_Bartender(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
02810 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
02811 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02812 NOTSOLID - Starts not solid
02813 STARTINSOLID - Don't try to fix if spawn in solid
02814 SHY - Spawner is shy
02815 */
02816 void SP_NPC_Bartender( gentity_t *self)
02817 {
02818         self->NPC_type = "Bartender";
02819 
02820         SP_NPC_spawner( self );
02821 }
02822 
02823 /*QUAKED NPC_MorganKatarn(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
02824 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
02825 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02826 NOTSOLID - Starts not solid
02827 STARTINSOLID - Don't try to fix if spawn in solid
02828 SHY - Spawner is shy
02829 */
02830 void SP_NPC_MorganKatarn( gentity_t *self)
02831 {
02832         self->NPC_type = "MorganKatarn";
02833 
02834         SP_NPC_spawner( self );
02835 }
02836 
02837 //=============================================================================================
02838 //ALLIES
02839 //=============================================================================================
02840 
02841 /*QUAKED NPC_Jedi(1 0 0) (-16 -16 -24) (16 16 40) TRAINER x x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
02842 TRAINER - Special Jedi- instructor
02843 CEILING - Sticks to the ceiling until he sees an enemy or takes pain
02844 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02845 NOTSOLID - Starts not solid
02846 STARTINSOLID - Don't try to fix if spawn in solid
02847 SHY - Spawner is shy
02848 
02849 Ally Jedi NPC Buddy - tags along with player
02850 */
02851 void SP_NPC_Jedi( gentity_t *self)
02852 {
02853         if(!self->NPC_type)
02854         {
02855                 if ( self->spawnflags & 1 )
02856                 {
02857                         self->NPC_type = "jeditrainer";
02858                 }
02859                 else 
02860                 {
02861                         /*
02862                         if ( !Q_irand( 0, 2 ) )
02863                         {
02864                                 self->NPC_type = "JediF";
02865                         }
02866                         else 
02867                         */if ( Q_irand( 0, 1 ) )
02868                         {
02869                                 self->NPC_type = "Jedi";
02870                         }
02871                         else
02872                         {
02873                                 self->NPC_type = "Jedi2";
02874                         }
02875                 }
02876         }
02877 
02878         WP_SetSaberModel( NULL, CLASS_JEDI );
02879 
02880         SP_NPC_spawner( self );
02881 }
02882 
02883 /*QUAKED NPC_Prisoner(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
02884 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
02885 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02886 NOTSOLID - Starts not solid
02887 STARTINSOLID - Don't try to fix if spawn in solid
02888 SHY - Spawner is shy
02889 */
02890 void SP_NPC_Prisoner( gentity_t *self)
02891 {
02892         if(!self->NPC_type)
02893         {
02894                 if ( Q_irand( 0, 1 ) )
02895                 {
02896                         self->NPC_type = "Prisoner";
02897                 }
02898                 else
02899                 {
02900                         self->NPC_type = "Prisoner2";
02901                 }
02902         }
02903 
02904         SP_NPC_spawner( self );
02905 }
02906 
02907 /*QUAKED NPC_Rebel(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
02908 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
02909 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02910 NOTSOLID - Starts not solid
02911 STARTINSOLID - Don't try to fix if spawn in solid
02912 SHY - Spawner is shy
02913 */
02914 void SP_NPC_Rebel( gentity_t *self)
02915 {
02916         if(!self->NPC_type)
02917         {
02918                 if ( Q_irand( 0, 1 ) )
02919                 {
02920                         self->NPC_type = "Rebel";
02921                 }
02922                 else
02923                 {
02924                         self->NPC_type = "Rebel2";
02925                 }
02926         }
02927 
02928         SP_NPC_spawner( self );
02929 }
02930 
02931 //=============================================================================================
02932 //ENEMIES
02933 //=============================================================================================
02934 
02935 /*QUAKED NPC_Stormtrooper(1 0 0) (-16 -16 -24) (16 16 40) OFFICER COMMANDER ALTOFFICER ROCKET DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
02936 30 health, blaster
02937 
02938 OFFICER - 60 health, flechette
02939 COMMANDER - 60 health, heavy repeater
02940 ALTOFFICER - 60 health, alt-fire flechette (grenades)
02941 ROCKET - 60 health, rocket launcher
02942 
02943 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
02944 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02945 NOTSOLID - Starts not solid
02946 STARTINSOLID - Don't try to fix if spawn in solid
02947 SHY - Spawner is shy
02948 */
02949 void SP_NPC_Stormtrooper( gentity_t *self)
02950 {
02951         if ( self->spawnflags & 8 )
02952         {//rocketer
02953                 self->NPC_type = "rockettrooper";
02954         }
02955         else if ( self->spawnflags & 4 )
02956         {//alt-officer
02957                 self->NPC_type = "stofficeralt";
02958         }
02959         else if ( self->spawnflags & 2 )
02960         {//commander
02961                 self->NPC_type = "stcommander";
02962         }
02963         else if ( self->spawnflags & 1 )
02964         {//officer
02965                 self->NPC_type = "stofficer";
02966         }
02967         else
02968         {//regular trooper
02969                 if ( Q_irand( 0, 1 ) )
02970                 {
02971                         self->NPC_type = "StormTrooper";
02972                 }
02973                 else
02974                 {
02975                         self->NPC_type = "StormTrooper2";
02976                 }
02977         }
02978 
02979         SP_NPC_spawner( self );
02980 }
02981 void SP_NPC_StormtrooperOfficer( gentity_t *self)
02982 {
02983         self->spawnflags |= 1;
02984         SP_NPC_Stormtrooper( self );
02985 }
02986 /*QUAKED NPC_Snowtrooper(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
02987 30 health, blaster
02988 
02989 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
02990 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
02991 NOTSOLID - Starts not solid
02992 STARTINSOLID - Don't try to fix if spawn in solid
02993 SHY - Spawner is shy
02994 */
02995 void SP_NPC_Snowtrooper( gentity_t *self)
02996 {
02997         self->NPC_type = "snowtrooper";
02998 
02999         SP_NPC_spawner( self );
03000 }
03001 /*QUAKED NPC_Tie_Pilot(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03002 30 health, blaster
03003 
03004 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03005 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03006 NOTSOLID - Starts not solid
03007 STARTINSOLID - Don't try to fix if spawn in solid
03008 SHY - Spawner is shy
03009 */
03010 void SP_NPC_Tie_Pilot( gentity_t *self)
03011 {
03012         self->NPC_type = "stormpilot";
03013 
03014         SP_NPC_spawner( self );
03015 }
03016 
03017 /*QUAKED NPC_Ugnaught(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03018 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03019 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03020 NOTSOLID - Starts not solid
03021 STARTINSOLID - Don't try to fix if spawn in solid
03022 SHY - Spawner is shy
03023 */
03024 void SP_NPC_Ugnaught( gentity_t *self)
03025 {
03026         if ( !self->NPC_type )
03027         {
03028                 if ( Q_irand( 0, 1 ) )
03029                 {
03030                         self->NPC_type = "Ugnaught";
03031                 }
03032                 else
03033                 {
03034                         self->NPC_type = "Ugnaught2";
03035                 }
03036         }
03037 
03038         SP_NPC_spawner( self );
03039 }
03040 
03041 /*QUAKED NPC_Jawa(1 0 0) (-16 -16 -24) (16 16 40) ARMED x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03042 ARMED - starts with the Jawa gun in-hand
03043 
03044 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03045 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03046 NOTSOLID - Starts not solid
03047 STARTINSOLID - Don't try to fix if spawn in solid
03048 SHY - Spawner is shy
03049 */
03050 void SP_NPC_Jawa( gentity_t *self)
03051 {
03052         if ( !self->NPC_type )
03053         {
03054                 if ( (self->spawnflags&1) )
03055                 {
03056                         self->NPC_type = "jawa_armed";
03057                 }
03058                 else
03059                 {
03060                         self->NPC_type = "jawa";
03061                 }
03062         }
03063 
03064         SP_NPC_spawner( self );
03065 }
03066 
03067 /*QUAKED NPC_Gran(1 0 0) (-16 -16 -24) (16 16 40) SHOOTER BOXER x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03068 Uses grenade
03069 
03070 SHOOTER - uses blaster instead of 
03071 BOXER - uses fists only
03072 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03073 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03074 NOTSOLID - Starts not solid
03075 STARTINSOLID - Don't try to fix if spawn in solid
03076 SHY - Spawner is shy
03077 */
03078 void SP_NPC_Gran( gentity_t *self)
03079 {
03080         if ( !self->NPC_type )
03081         {
03082                 if ( self->spawnflags & 1 )
03083                 {
03084                         self->NPC_type = "granshooter";
03085                 }
03086                 else if ( self->spawnflags & 2 )
03087                 {
03088                         self->NPC_type = "granboxer";
03089                 }
03090                 else
03091                 {
03092                         if ( Q_irand( 0, 1 ) )
03093                         {
03094                                 self->NPC_type = "gran";
03095                         }
03096                         else
03097                         {
03098                                 self->NPC_type = "gran2";
03099                         }
03100                 }
03101         }
03102 
03103         SP_NPC_spawner( self );
03104 }
03105 
03106 /*QUAKED NPC_Rodian(1 0 0) (-16 -16 -24) (16 16 40) BLASTER NO_HIDE x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03107 BLASTER uses a blaster instead of sniper rifle, different skin
03108 NO_HIDE (only applicable with snipers) does not duck and hide between shots
03109 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03110 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03111 NOTSOLID - Starts not solid
03112 STARTINSOLID - Don't try to fix if spawn in solid
03113 SHY - Spawner is shy
03114 */
03115 void SP_NPC_Rodian( gentity_t *self)
03116 {
03117         if ( !self->NPC_type )
03118         {
03119                 if ( self->spawnflags&1 )
03120                 {
03121                         self->NPC_type = "rodian2";
03122                 }
03123                 else
03124                 {
03125                         self->NPC_type = "rodian";
03126                 }
03127         }
03128 
03129         SP_NPC_spawner( self );
03130 }
03131 
03132 /*QUAKED NPC_Weequay(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03133 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03134 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03135 NOTSOLID - Starts not solid
03136 STARTINSOLID - Don't try to fix if spawn in solid
03137 SHY - Spawner is shy
03138 */
03139 void SP_NPC_Weequay( gentity_t *self)
03140 {
03141         if ( !self->NPC_type )
03142         {
03143                 switch ( Q_irand( 0, 3 ) )
03144                 {
03145                 case 0:
03146                         self->NPC_type = "Weequay";
03147                         break;
03148                 case 1:
03149                         self->NPC_type = "Weequay2";
03150                         break;
03151                 case 2:
03152                         self->NPC_type = "Weequay3";
03153                         break;
03154                 case 3:
03155                         self->NPC_type = "Weequay4";
03156                         break;
03157                 }
03158         }
03159 
03160         SP_NPC_spawner( self );
03161 }
03162 
03163 /*QUAKED NPC_Trandoshan(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03164 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03165 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03166 NOTSOLID - Starts not solid
03167 STARTINSOLID - Don't try to fix if spawn in solid
03168 SHY - Spawner is shy
03169 */
03170 void SP_NPC_Trandoshan( gentity_t *self)
03171 {
03172         if ( !self->NPC_type )
03173         {
03174                 self->NPC_type = "Trandoshan";
03175         }
03176 
03177         SP_NPC_spawner( self );
03178 }
03179 
03180 /*QUAKED NPC_Tusken(1 0 0) (-16 -16 -24) (16 16 40) SNIPER x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03181 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03182 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03183 NOTSOLID - Starts not solid
03184 STARTINSOLID - Don't try to fix if spawn in solid
03185 SHY - Spawner is shy
03186 */
03187 void SP_NPC_Tusken( gentity_t *self)
03188 {
03189         if ( !self->NPC_type )
03190         {
03191                 if ( (self->spawnflags&1) )
03192                 {
03193                         self->NPC_type = "tuskensniper";
03194                 }
03195                 else
03196                 {
03197                         self->NPC_type = "tusken";
03198                 }
03199         }
03200 
03201         SP_NPC_spawner( self );
03202 }
03203 
03204 /*QUAKED NPC_Noghri(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03205 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03206 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03207 NOTSOLID - Starts not solid
03208 STARTINSOLID - Don't try to fix if spawn in solid
03209 SHY - Spawner is shy
03210 */
03211 void SP_NPC_Noghri( gentity_t *self)
03212 {
03213         if ( !self->NPC_type )
03214         {
03215                 self->NPC_type = "noghri";
03216         }
03217 
03218         SP_NPC_spawner( self );
03219 }
03220 
03221 /*QUAKED NPC_SwampTrooper(1 0 0) (-16 -16 -24) (16 16 40) REPEATER x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03222 REPEATER - Swaptrooper who uses the repeater
03223 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03224 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03225 NOTSOLID - Starts not solid
03226 STARTINSOLID - Don't try to fix if spawn in solid
03227 SHY - Spawner is shy
03228 */
03229 void SP_NPC_SwampTrooper( gentity_t *self)
03230 {
03231         if ( !self->NPC_type )
03232         {
03233                 if ( self->spawnflags & 1 )
03234                 {
03235                         self->NPC_type = "SwampTrooper2";
03236                 }
03237                 else
03238                 {
03239                         self->NPC_type = "SwampTrooper";
03240                 }
03241         }
03242 
03243         SP_NPC_spawner( self );
03244 }
03245 
03246 /*QUAKED NPC_Imperial(1 0 0) (-16 -16 -24) (16 16 40) OFFICER COMMANDER x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03247 
03248 Greyshirt grunt, uses blaster pistol, 20 health.
03249 
03250 OFFICER - Brownshirt Officer, uses blaster rifle, 40 health
03251 COMMANDER - Blackshirt Commander, uses rapid-fire blaster rifle, 80 healt
03252 
03253 "message" - if a COMMANDER, turns on his key surface.  This is the name of the key you get when you walk over his body.  This must match the "message" field of the func_security_panel you want this key to open.  Set to "goodie" to have him carrying a goodie key that player can use to operate doors with "GOODIE" spawnflag.
03254 
03255 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03256 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03257 NOTSOLID - Starts not solid
03258 STARTINSOLID - Don't try to fix if spawn in solid
03259 SHY - Spawner is shy
03260 */
03261 void SP_NPC_Imperial( gentity_t *self)
03262 {
03263         if ( !self->NPC_type )
03264         {
03265                 if ( self->spawnflags & 1 )
03266                 {
03267                         self->NPC_type = "ImpOfficer";
03268                 }
03269                 else if ( self->spawnflags & 2 )
03270                 {
03271                         self->NPC_type = "ImpCommander";
03272                 }
03273                 else
03274                 {
03275                         self->NPC_type = "Imperial";
03276                 }
03277         }
03278 
03279         /*
03280         if ( self->message )
03281         {//may drop a key, precache the key model and pickup sound
03282                 G_SoundIndex( "sound/weapons/key_pkup.wav" );
03283                 if ( !Q_stricmp( "goodie", self->message ) )
03284                 {
03285                         RegisterItem( FindItemForInventory( INV_GOODIE_KEY ) );
03286                 }
03287                 else
03288                 {
03289                         RegisterItem( FindItemForInventory( INV_SECURITY_KEY ) );
03290                 }
03291         }
03292         */
03293         //rwwFIXMEFIXME: Allow goodie keys
03294         SP_NPC_spawner( self );
03295 }
03296 
03297 /*QUAKED NPC_ImpWorker(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03298 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03299 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03300 NOTSOLID - Starts not solid
03301 STARTINSOLID - Don't try to fix if spawn in solid
03302 SHY - Spawner is shy
03303 */
03304 void SP_NPC_ImpWorker( gentity_t *self)
03305 {
03306         if ( !self->NPC_type )
03307         {
03308                 if ( !Q_irand( 0, 2 ) )
03309                 {
03310                         self->NPC_type = "ImpWorker";
03311                 }
03312                 else if ( Q_irand( 0, 1 ) )
03313                 {
03314                         self->NPC_type = "ImpWorker2";
03315                 }
03316                 else
03317                 {
03318                         self->NPC_type = "ImpWorker3";
03319                 }
03320         }
03321 
03322         SP_NPC_spawner( self );
03323 }
03324 
03325 /*QUAKED NPC_BespinCop(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03326 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03327 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03328 NOTSOLID - Starts not solid
03329 STARTINSOLID - Don't try to fix if spawn in solid
03330 SHY - Spawner is shy
03331 */
03332 void SP_NPC_BespinCop( gentity_t *self)
03333 {
03334         if ( !self->NPC_type )
03335         {
03336                 if ( !Q_irand( 0, 1 ) )
03337                 {
03338                         self->NPC_type = "BespinCop";
03339                 }
03340                 else
03341                 {
03342                         self->NPC_type = "BespinCop2";
03343                 }
03344         }
03345 
03346         SP_NPC_spawner( self );
03347 }
03348 
03349 /*QUAKED NPC_Reborn(1 0 0) (-16 -16 -24) (16 16 40) FORCE FENCER ACROBAT BOSS CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
03350 
03351 Default Reborn is A poor lightsaber fighter, acrobatic and uses no force powers.  Yellow saber, 40 health.
03352 
03353 FORCE - Uses force powers but is not the best lightsaber fighter and not acrobatic.  Purple saber, 75 health.
03354 FENCER - A good lightsaber fighter, but not acrobatic and uses no force powers.  Yellow saber, 100 health.
03355 ACROBAT - quite acrobatic, but not the best lightsaber fighter and uses no force powers.  Red saber, 100 health.
03356 BOSS - quite acrobatic, good lightsaber fighter and uses force powers.  Orange saber, 150 health.
03357 
03358 NOTE: Saber colors are temporary until they have different by skins to tell them apart
03359 
03360 CEILING - Sticks to the ceiling until he sees an enemy or takes pain
03361 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03362 NOTSOLID - Starts not solid
03363 STARTINSOLID - Don't try to fix if spawn in solid
03364 SHY - Spawner is shy
03365 */
03366 void SP_NPC_Reborn( gentity_t *self)
03367 {
03368         if ( !self->NPC_type )
03369         {
03370                 if ( self->spawnflags & 1 )
03371                 {
03372                         self->NPC_type = "rebornforceuser";
03373                 }
03374                 else if ( self->spawnflags & 2 )
03375                 {
03376                         self->NPC_type = "rebornfencer";
03377                 }
03378                 else if ( self->spawnflags & 4 )
03379                 {
03380                         self->NPC_type = "rebornacrobat";
03381                 }
03382                 else if ( self->spawnflags & 8 )
03383                 {
03384                         self->NPC_type = "rebornboss";
03385                 }
03386                 else
03387                 {
03388                         self->NPC_type = "reborn";
03389                 }
03390         }
03391         
03392         WP_SetSaberModel( NULL, CLASS_REBORN );
03393         SP_NPC_spawner( self );
03394 }
03395 
03396 /*QUAKED NPC_ShadowTrooper(1 0 0) (-16 -16 -24) (16 16 40) x x x x CEILING CINEMATIC NOTSOLID STARTINSOLID SHY
03397 CEILING - Sticks to the ceiling until he sees an enemy or takes pain
03398 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03399 NOTSOLID - Starts not solid
03400 STARTINSOLID - Don't try to fix if spawn in solid
03401 SHY - Spawner is shy
03402 */
03403 void SP_NPC_ShadowTrooper( gentity_t *self)
03404 {
03405         if(!self->NPC_type)
03406         {
03407                 if ( !Q_irand( 0, 1 ) )
03408                 {
03409                         self->NPC_type = "ShadowTrooper";
03410                 }
03411                 else
03412                 {
03413                         self->NPC_type = "ShadowTrooper2";
03414                 }
03415         }
03416         
03417         NPC_ShadowTrooper_Precache();
03418         WP_SetSaberModel( NULL, CLASS_SHADOWTROOPER );
03419 
03420         SP_NPC_spawner( self );
03421 }
03422 //=============================================================================================
03423 //MONSTERS
03424 //=============================================================================================
03425 
03426 /*QUAKED NPC_Monster_Murjj (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03427 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03428 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03429 NOTSOLID - Starts not solid
03430 STARTINSOLID - Don't try to fix if spawn in solid
03431 SHY - Spawner is shy
03432 */
03433 void SP_NPC_Monster_Murjj( gentity_t *self)
03434 {
03435         self->NPC_type = "Murjj";
03436 
03437         SP_NPC_spawner( self );
03438 }
03439 
03440 /*QUAKED NPC_Monster_Swamp (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03441 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03442 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03443 NOTSOLID - Starts not solid
03444 STARTINSOLID - Don't try to fix if spawn in solid
03445 SHY - Spawner is shy
03446 */
03447 void SP_NPC_Monster_Swamp( gentity_t *self)
03448 {
03449         self->NPC_type = "Swamp";
03450 
03451         SP_NPC_spawner( self );
03452 }
03453 
03454 /*QUAKED NPC_Monster_Howler (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03455 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03456 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03457 NOTSOLID - Starts not solid
03458 STARTINSOLID - Don't try to fix if spawn in solid
03459 SHY - Spawner is shy
03460 */
03461 void SP_NPC_Monster_Howler( gentity_t *self)
03462 {
03463         self->NPC_type = "howler";
03464 
03465         SP_NPC_spawner( self );
03466 }
03467 
03468 /*QUAKED NPC_MineMonster (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03469 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03470 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03471 NOTSOLID - Starts not solid
03472 STARTINSOLID - Don't try to fix if spawn in solid
03473 SHY - Spawner is shy
03474 */
03475 void SP_NPC_MineMonster( gentity_t *self)
03476 {
03477         self->NPC_type = "minemonster";
03478 
03479         SP_NPC_spawner( self );
03480         NPC_MineMonster_Precache();
03481 }
03482 
03483 /*QUAKED NPC_Monster_Claw (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03484 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03485 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03486 NOTSOLID - Starts not solid
03487 STARTINSOLID - Don't try to fix if spawn in solid
03488 SHY - Spawner is shy
03489 */
03490 void SP_NPC_Monster_Claw( gentity_t *self)
03491 {
03492         self->NPC_type = "Claw";
03493 
03494         SP_NPC_spawner( self );
03495 }
03496 
03497 /*QUAKED NPC_Monster_Glider (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03498 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03499 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03500 NOTSOLID - Starts not solid
03501 STARTINSOLID - Don't try to fix if spawn in solid
03502 SHY - Spawner is shy
03503 */
03504 void SP_NPC_Monster_Glider( gentity_t *self)
03505 {
03506         self->NPC_type = "Glider";
03507 
03508         SP_NPC_spawner( self );
03509 }
03510 
03511 /*QUAKED NPC_Monster_Flier2 (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03512 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03513 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03514 NOTSOLID - Starts not solid
03515 STARTINSOLID - Don't try to fix if spawn in solid
03516 SHY - Spawner is shy
03517 */
03518 void SP_NPC_Monster_Flier2( gentity_t *self)
03519 {
03520         self->NPC_type = "Flier2";
03521 
03522         SP_NPC_spawner( self );
03523 }
03524 
03525 /*QUAKED NPC_Monster_Lizard (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03526 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03527 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03528 NOTSOLID - Starts not solid
03529 STARTINSOLID - Don't try to fix if spawn in solid
03530 SHY - Spawner is shy
03531 */
03532 void SP_NPC_Monster_Lizard( gentity_t *self)
03533 {
03534         self->NPC_type = "Lizard";
03535 
03536         SP_NPC_spawner( self );
03537 }
03538 
03539 /*QUAKED NPC_Monster_Fish (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03540 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03541 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03542 NOTSOLID - Starts not solid
03543 STARTINSOLID - Don't try to fix if spawn in solid
03544 SHY - Spawner is shy
03545 */
03546 void SP_NPC_Monster_Fish( gentity_t *self)
03547 {
03548         self->NPC_type = "Fish";
03549 
03550         SP_NPC_spawner( self );
03551 }
03552 
03553 /*QUAKED NPC_Monster_Wampa (1 0 0) (-12 -12 -24) (12 12 40) WANDER SEARCH x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03554 WANDER - When I don't have an enemy, I'll just wander the waypoint network aimlessly
03555 SEARCH - When I don't have an enemy, I'll go back and forth between the nearest waypoints, looking for enemies
03556 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03557 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03558 NOTSOLID - Starts not solid
03559 STARTINSOLID - Don't try to fix if spawn in solid
03560 SHY - Spawner is shy
03561 */
03562 void SP_NPC_Monster_Wampa( gentity_t *self)
03563 {
03564         self->NPC_type = "wampa";
03565 
03566         NPC_Wampa_Precache();
03567 
03568         SP_NPC_spawner( self );
03569 }
03570 
03571 /*QUAKED NPC_Monster_Rancor (1 0 0) (-30 -30 -24) (30 30 104) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03572 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03573 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03574 NOTSOLID - Starts not solid
03575 STARTINSOLID - Don't try to fix if spawn in solid
03576 SHY - Spawner is shy
03577 */
03578 void SP_NPC_Monster_Rancor( gentity_t *self)
03579 {
03580         self->NPC_type = "rancor";
03581 
03582         SP_NPC_spawner( self );
03583 }
03584 
03585 //=============================================================================================
03586 //DROIDS
03587 //=============================================================================================
03588 
03589 /*QUAKED NPC_Droid_Interrogator (1 0 0) (-12 -12 -24) (12 12 0) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03590 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03591 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03592 NOTSOLID - Starts not solid
03593 STARTINSOLID - Don't try to fix if spawn in solid
03594 SHY - Spawner is shy
03595 */
03596 void SP_NPC_Droid_Interrogator( gentity_t *self)
03597 {
03598         self->NPC_type = "interrogator";
03599 
03600         SP_NPC_spawner( self );
03601 
03602         NPC_Interrogator_Precache(self);
03603 }
03604 
03605 /*QUAKED NPC_Droid_Probe (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03606 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03607 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03608 NOTSOLID - Starts not solid
03609 STARTINSOLID - Don't try to fix if spawn in solid
03610 SHY - Spawner is shy
03611 
03612 Imperial Probe Droid - the multilegged floating droid that Han and Chewie shot on the ice planet Hoth
03613 */
03614 void SP_NPC_Droid_Probe( gentity_t *self)
03615 {
03616         self->NPC_type = "probe";
03617 
03618         SP_NPC_spawner( self );
03619 
03620         NPC_Probe_Precache();
03621 }
03622 
03623 /*QUAKED NPC_Droid_Mark1 (1 0 0) (-36 -36 -24) (36 36 80) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03624 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03625 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03626 NOTSOLID - Starts not solid
03627 STARTINSOLID - Don't try to fix if spawn in solid
03628 SHY - Spawner is shy
03629 
03630 Big walking droid
03631 
03632 */
03633 void SP_NPC_Droid_Mark1( gentity_t *self)
03634 {
03635         self->NPC_type = "mark1";
03636 
03637         SP_NPC_spawner( self );
03638 
03639         NPC_Mark1_Precache();
03640 }
03641 
03642 /*QUAKED NPC_Droid_Mark2 (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03643 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03644 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03645 NOTSOLID - Starts not solid
03646 STARTINSOLID - Don't try to fix if spawn in solid
03647 SHY - Spawner is shy
03648 
03649 Small rolling droid with one gun.
03650 
03651 */
03652 void SP_NPC_Droid_Mark2( gentity_t *self)
03653 {
03654         self->NPC_type = "mark2";
03655 
03656         SP_NPC_spawner( self );
03657 
03658         NPC_Mark2_Precache();
03659 }
03660 
03661 /*QUAKED NPC_Droid_ATST (1 0 0) (-40 -40 -24) (40 40 248) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03662 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03663 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03664 NOTSOLID - Starts not solid
03665 STARTINSOLID - Don't try to fix if spawn in solid
03666 SHY - Spawner is shy
03667 */
03668 void SP_NPC_Droid_ATST( gentity_t *self)
03669 {
03670         if ( (self->spawnflags&1) )
03671         {
03672                 self->NPC_type = "atst_vehicle";
03673         }
03674         else
03675         {
03676                 self->NPC_type = "atst";
03677         }
03678 
03679         SP_NPC_spawner( self );
03680 
03681         NPC_ATST_Precache();
03682 }
03683 
03684 /*QUAKED NPC_Droid_Remote (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03685 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03686 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03687 NOTSOLID - Starts not solid
03688 STARTINSOLID - Don't try to fix if spawn in solid
03689 SHY - Spawner is shy
03690 
03691 Remote Droid - the floating round droid used by Obi Wan to train Luke about the force while on the Millenium Falcon.
03692 */
03693 void SP_NPC_Droid_Remote( gentity_t *self)
03694 {
03695         self->NPC_type = "remote";
03696 
03697         SP_NPC_spawner( self );
03698 
03699         NPC_Remote_Precache();
03700 }
03701 
03702 /*QUAKED NPC_Droid_Seeker (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03703 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03704 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03705 NOTSOLID - Starts not solid
03706 STARTINSOLID - Don't try to fix if spawn in solid
03707 SHY - Spawner is shy
03708 
03709 Seeker Droid - floating round droids that shadow troopers spawn
03710 */
03711 void SP_NPC_Droid_Seeker( gentity_t *self)
03712 {
03713         self->NPC_type = "seeker";
03714 
03715         SP_NPC_spawner( self );
03716 
03717         NPC_Seeker_Precache();
03718 }
03719 
03720 /*QUAKED NPC_Droid_Sentry (1 0 0) (-24 -24 -24) (24 24 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03721 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03722 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03723 NOTSOLID - Starts not solid
03724 STARTINSOLID - Don't try to fix if spawn in solid
03725 SHY - Spawner is shy
03726 
03727 Sentry Droid - Large, armored floating Imperial droids with 3 forward-facing gun turrets
03728 */
03729 void SP_NPC_Droid_Sentry( gentity_t *self)
03730 {
03731         self->NPC_type = "sentry";
03732 
03733         SP_NPC_spawner( self );
03734 
03735         NPC_Sentry_Precache();
03736 }
03737 
03738 /*QUAKED NPC_Droid_Gonk (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03739 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03740 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03741 NOTSOLID - Starts not solid
03742 STARTINSOLID - Don't try to fix if spawn in solid
03743 SHY - Spawner is shy
03744 
03745 Gonk Droid - the droid that looks like a walking ice machine. Was in the Jawa land crawler, walking around talking to itself.
03746 
03747 NOTARGET by default
03748 */
03749 void SP_NPC_Droid_Gonk( gentity_t *self)
03750 {
03751         self->NPC_type = "gonk";
03752 
03753         SP_NPC_spawner( self );
03754 
03755         //precache the Gonk sounds
03756         NPC_Gonk_Precache();
03757 }
03758 
03759 /*QUAKED NPC_Droid_Mouse (1 0 0) (-12 -12 -24) (12 12 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03760 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03761 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03762 NOTSOLID - Starts not solid
03763 STARTINSOLID - Don't try to fix if spawn in solid
03764 SHY - Spawner is shy
03765 
03766 Mouse Droid - small, box shaped droid, first seen on the Death Star. Chewie yelled at it and it backed up and ran away.
03767 
03768 NOTARGET by default
03769 */
03770 void SP_NPC_Droid_Mouse( gentity_t *self)
03771 {
03772         self->NPC_type = "mouse";
03773 
03774         SP_NPC_spawner( self );
03775 
03776         //precache the Mouse sounds
03777         NPC_Mouse_Precache();
03778 
03779 }
03780 
03781 /*QUAKED NPC_Droid_R2D2 (1 0 0) (-12 -12 -24) (12 12 40) IMPERIAL x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03782 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03783 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03784 NOTSOLID - Starts not solid
03785 STARTINSOLID - Don't try to fix if spawn in solid
03786 SHY - Spawner is shy
03787 
03788 R2D2 Droid - you probably know this one already. 
03789 
03790 NOTARGET by default
03791 */
03792 void SP_NPC_Droid_R2D2( gentity_t *self)
03793 {
03794         if ( self->spawnflags&1 )
03795         {//imperial skin
03796                 self->NPC_type = "r2d2_imp";
03797         }
03798         else
03799         {
03800                 self->NPC_type = "r2d2";
03801         }
03802 
03803         SP_NPC_spawner( self );
03804 
03805         NPC_R2D2_Precache();
03806 }
03807 
03808 /*QUAKED NPC_Droid_R5D2 (1 0 0) (-12 -12 -24) (12 12 40) IMPERIAL ALWAYSDIE x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03809 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03810 ALWAYSDIE - won't go into spinning zombie AI when at low health.
03811 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03812 NOTSOLID - Starts not solid
03813 STARTINSOLID - Don't try to fix if spawn in solid
03814 SHY - Spawner is shy
03815 
03816 R5D2 Droid - the droid originally chosen by Uncle Owen until it blew a bad motivator, and they took R2D2 instead.
03817 
03818 NOTARGET by default
03819 */
03820 void SP_NPC_Droid_R5D2( gentity_t *self)
03821 {
03822         if ( self->spawnflags&1 )
03823         {//imperial skin
03824                 self->NPC_type = "r5d2_imp";
03825         }
03826         else
03827         {
03828                 self->NPC_type = "r5d2";
03829         }
03830 
03831         SP_NPC_spawner( self );
03832 
03833         NPC_R5D2_Precache();
03834 }
03835 
03836 /*QUAKED NPC_Droid_Protocol (1 0 0) (-12 -12 -24) (12 12 40) IMPERIAL x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY
03837 DROPTOFLOOR - NPC can be in air, but will spawn on the closest floor surface below it
03838 CINEMATIC - Will spawn with no default AI (BS_CINEMATIC)
03839 NOTSOLID - Starts not solid
03840 STARTINSOLID - Don't try to fix if spawn in solid
03841 SHY - Spawner is shy
03842 
03843 NOTARGET by default
03844 */
03845 void SP_NPC_Droid_Protocol( gentity_t *self)
03846 {
03847         if ( self->spawnflags&1 )
03848         {//imperial skin
03849                 self->NPC_type = "protocol_imp";
03850         }
03851         else
03852         {
03853                 self->NPC_type = "protocol";
03854         }
03855 
03856         SP_NPC_spawner( self );
03857         NPC_Protocol_Precache();
03858 }
03859 
03860 
03861 //NPC console commands
03862 /*
03863 NPC_Spawn_f
03864 */
03865 
03866 gentity_t *NPC_SpawnType( gentity_t *ent, char *npc_type, char *targetname, qboolean isVehicle ) 
03867 {
03868         gentity_t               *NPCspawner = G_Spawn();
03869         vec3_t                  forward, end;
03870         trace_t                 trace;
03871 
03872         if(!NPCspawner)
03873         {
03874                 Com_Printf( S_COLOR_RED"NPC_Spawn Error: Out of entities!\n" );
03875                 return NULL;
03876         }
03877 
03878         NPCspawner->think = G_FreeEntity;
03879         NPCspawner->nextthink = level.time + FRAMETIME;
03880         
03881         if ( !npc_type )
03882         {
03883                 return NULL;
03884         }
03885 
03886         if (!npc_type[0])
03887         {
03888                 Com_Printf( S_COLOR_RED"Error, expected one of:\n"S_COLOR_WHITE" NPC spawn [NPC type (from ext_data/NPCs)]\n NPC spawn vehicle [VEH type (from ext_data/vehicles)]\n" );
03889                 return NULL;
03890         }
03891 
03892         if ( !ent || !ent->client )
03893         {//screw you, go away
03894                 return NULL;
03895         }
03896 
03897         //rwwFIXMEFIXME: Care about who is issuing this command/other clients besides 0?
03898         //Spawn it at spot of first player
03899         //FIXME: will gib them!
03900         AngleVectors(ent->client->ps.viewangles, forward, NULL, NULL);
03901         VectorNormalize(forward);
03902         VectorMA(ent->r.currentOrigin, 64, forward, end);
03903         trap_Trace(&trace, ent->r.currentOrigin, NULL, NULL, end, 0, MASK_SOLID);
03904         VectorCopy(trace.endpos, end);
03905         end[2] -= 24;
03906         trap_Trace(&trace, trace.endpos, NULL, NULL, end, 0, MASK_SOLID);
03907         VectorCopy(trace.endpos, end);
03908         end[2] += 24;
03909         G_SetOrigin(NPCspawner, end);
03910         VectorCopy(NPCspawner->r.currentOrigin, NPCspawner->s.origin);
03911         //set the yaw so that they face away from player
03912         NPCspawner->s.angles[1] = ent->client->ps.viewangles[1];
03913 
03914         trap_LinkEntity(NPCspawner);
03915 
03916         NPCspawner->NPC_type = G_NewString( npc_type );
03917 
03918         if ( targetname )
03919         {
03920                 NPCspawner->NPC_targetname = G_NewString(targetname);
03921         }
03922 
03923         NPCspawner->count = 1;
03924 
03925         NPCspawner->delay = 0;
03926 
03927         //NPCspawner->spawnflags |= SFB_NOTSOLID;
03928 
03929         //NPCspawner->playerTeam = TEAM_FREE;
03930         //NPCspawner->behaviorSet[BSET_SPAWN] = "common/guard";
03931         
03932         if ( isVehicle )
03933         {
03934                 NPCspawner->classname = "NPC_Vehicle";
03935         }
03936 
03937         //call precache funcs for James' builds
03938         if ( !Q_stricmp( "gonk", NPCspawner->NPC_type))
03939         {
03940                 NPC_Gonk_Precache();
03941         }
03942         else if ( !Q_stricmp( "mouse", NPCspawner->NPC_type))
03943         {
03944                 NPC_Mouse_Precache();
03945         }
03946         else if ( !Q_strncmp( "r2d2", NPCspawner->NPC_type, 4))
03947         {
03948                 NPC_R2D2_Precache();
03949         }
03950         else if ( !Q_stricmp( "atst", NPCspawner->NPC_type))
03951         {
03952                 NPC_ATST_Precache();
03953         }
03954         else if ( !Q_strncmp( "r5d2", NPCspawner->NPC_type, 4))
03955         {
03956                 NPC_R5D2_Precache();
03957         }
03958         else if ( !Q_stricmp( "mark1", NPCspawner->NPC_type))
03959         {
03960                 NPC_Mark1_Precache();
03961         }
03962         else if ( !Q_stricmp( "mark2", NPCspawner->NPC_type))
03963         {
03964                 NPC_Mark2_Precache();
03965         }
03966         else if ( !Q_stricmp( "interrogator", NPCspawner->NPC_type))
03967         {
03968                 NPC_Interrogator_Precache(NULL);
03969         }
03970         else if ( !Q_stricmp( "probe", NPCspawner->NPC_type))
03971         {
03972                 NPC_Probe_Precache();
03973         }
03974         else if ( !Q_stricmp( "seeker", NPCspawner->NPC_type))
03975         {
03976                 NPC_Seeker_Precache();
03977         }
03978         else if ( !Q_stricmp( "remote", NPCspawner->NPC_type))
03979         {
03980                 NPC_Remote_Precache();
03981         }
03982         else if ( !Q_strncmp( "shadowtrooper", NPCspawner->NPC_type, 13 ) )
03983         {
03984                 NPC_ShadowTrooper_Precache();
03985         }
03986         else if ( !Q_stricmp( "minemonster", NPCspawner->NPC_type ))
03987         {
03988                 NPC_MineMonster_Precache();
03989         }
03990         else if ( !Q_stricmp( "howler", NPCspawner->NPC_type ))
03991         {
03992                 NPC_Howler_Precache();
03993         }
03994         else if ( !Q_stricmp( "sentry", NPCspawner->NPC_type ))
03995         {
03996                 NPC_Sentry_Precache();
03997         }
03998         else if ( !Q_stricmp( "protocol", NPCspawner->NPC_type ))
03999         {
04000                 NPC_Protocol_Precache();
04001         }
04002         else if ( !Q_stricmp( "galak_mech", NPCspawner->NPC_type ))
04003         {
04004                 NPC_GalakMech_Precache();
04005         }
04006         else if ( !Q_stricmp( "wampa", NPCspawner->NPC_type ))
04007         {
04008                 NPC_Wampa_Precache();
04009         }
04010 
04011         return (NPC_Spawn_Do( NPCspawner ));
04012 }
04013 
04014 void NPC_Spawn_f( gentity_t *ent ) 
04015 {
04016         char    npc_type[1024];
04017         char    targetname[1024];
04018         qboolean        isVehicle = qfalse;
04019 
04020         trap_Argv(2, npc_type, 1024);
04021         if ( Q_stricmp( "vehicle", npc_type ) == 0 )
04022         {
04023                 isVehicle = qtrue;
04024                 trap_Argv(3, npc_type, 1024);
04025                 trap_Argv(4, targetname, 1024);
04026         }
04027         else
04028         {
04029                 trap_Argv(3, targetname, 1024);
04030         }
04031 
04032         NPC_SpawnType( ent, npc_type, targetname, isVehicle );
04033 }
04034 
04035 /*
04036 NPC_Kill_f
04037 */
04038 extern stringID_table_t TeamTable[];
04039 void NPC_Kill_f( void ) 
04040 {
04041         int                     n;
04042         gentity_t       *player;
04043         char            name[1024];
04044         team_t          killTeam = TEAM_FREE;
04045         qboolean        killNonSF = qfalse;
04046 
04047         trap_Argv(2, name, 1024);
04048 
04049         if ( !name[0] )
04050         {
04051                 Com_Printf( S_COLOR_RED"Error, Expected:\n");
04052                 Com_Printf( S_COLOR_RED"NPC kill '[NPC targetname]' - kills NPCs with certain targetname\n" );
04053                 Com_Printf( S_COLOR_RED"or\n" );
04054                 Com_Printf( S_COLOR_RED"NPC kill 'all' - kills all NPCs\n" );
04055                 Com_Printf( S_COLOR_RED"or\n" );
04056                 Com_Printf( S_COLOR_RED"NPC team '[teamname]' - kills all NPCs of a certain team ('nonally' is all but your allies)\n" );
04057                 return;
04058         }
04059 
04060         if ( Q_stricmp( "team", name ) == 0 )
04061         {
04062                 trap_Argv(3, name, 1024);
04063 
04064                 if ( !name[0] )
04065                 {
04066                         Com_Printf( S_COLOR_RED"NPC_Kill Error: 'npc kill team' requires a team name!\n" );
04067                         Com_Printf( S_COLOR_RED"Valid team names are:\n");
04068                         for ( n = (TEAM_FREE + 1); n < TEAM_NUM_TEAMS; n++ )
04069                         {
04070                                 Com_Printf( S_COLOR_RED"%s\n", TeamNames[n] );
04071                         }
04072                         Com_Printf( S_COLOR_RED"nonally - kills all but your teammates\n" );
04073                         return;
04074                 }
04075 
04076                 if ( Q_stricmp( "nonally", name ) == 0 )
04077                 {
04078                         killNonSF = qtrue;
04079                 }
04080                 else
04081                 {
04082                         killTeam = (team_t)GetIDForString( TeamTable, name );
04083 
04084                         if ( killTeam == TEAM_FREE )
04085                         {
04086                                 Com_Printf( S_COLOR_RED"NPC_Kill Error: team '%s' not recognized\n", name );
04087                                 Com_Printf( S_COLOR_RED"Valid team names are:\n");
04088                                 for ( n = (TEAM_FREE + 1); n < TEAM_NUM_TEAMS; n++ )
04089                                 {
04090                                         Com_Printf( S_COLOR_RED"%s\n", TeamNames[n] );
04091                                 }
04092                                 Com_Printf( S_COLOR_RED"nonally - kills all but your teammates\n" );
04093                                 return;
04094                         }
04095                 }
04096         }
04097 
04098         for ( n = 1; n < ENTITYNUM_MAX_NORMAL; n++) 
04099         {
04100                 player = &g_entities[n];
04101                 if (!player->inuse) {
04102                         continue;
04103                 }
04104                 if ( killNonSF )
04105                 {
04106                         if ( player )
04107                         {
04108                                 if ( player->client )
04109                                 {
04110                                         if ( player->client->playerTeam != NPCTEAM_PLAYER )
04111                                         {
04112                                                 Com_Printf( S_COLOR_GREEN"Killing NPC %s named %s\n", player->NPC_type, player->targetname );
04113                                                 player->health = 0;
04114 
04115                                                 if (player->die && player->client)
04116                                                 {
04117                                                         player->die(player, player, player, player->client->pers.maxHealth, MOD_UNKNOWN);
04118                                                 }
04119                                         }
04120                                 }
04121                                 else if ( player->NPC_type && player->classname && player->classname[0] && Q_stricmp( "NPC_starfleet", player->classname ) != 0 )
04122                                 {//A spawner, remove it
04123                                         Com_Printf( S_COLOR_GREEN"Removing NPC spawner %s with NPC named %s\n", player->NPC_type, player->NPC_targetname );
04124                                         G_FreeEntity( player );
04125                                         //FIXME: G_UseTargets2(player, player, player->NPC_target & player->target);?
04126                                 }
04127                         }
04128                 }
04129                 else if ( player && player->NPC && player->client )
04130                 {
04131                         if ( killTeam != TEAM_FREE )
04132                         {
04133                                 if ( player->client->playerTeam == killTeam )
04134                                 {
04135                                         Com_Printf( S_COLOR_GREEN"Killing NPC %s named %s\n", player->NPC_type, player->targetname );
04136                                         player->health = 0;
04137                                         if (player->die)
04138                                         {
04139                                                 player->die(player, player, player, player->client->pers.maxHealth, MOD_UNKNOWN);
04140                                         }
04141                                 }
04142                         }
04143                         else if( (player->targetname && Q_stricmp( name, player->targetname ) == 0)
04144                                 || Q_stricmp( name, "all" ) == 0 )
04145                         {
04146                                 Com_Printf( S_COLOR_GREEN"Killing NPC %s named %s\n", player->NPC_type, player->targetname );
04147                                 player->health = 0;
04148                                 player->client->ps.stats[STAT_HEALTH] = 0;
04149                                 if (player->die)
04150                                 {
04151                                         player->die(player, player, player, 100, MOD_UNKNOWN);
04152                                 }
04153                         }
04154                 }
04155                 /*
04156                 else if ( player && (player->r.svFlags&SVF_NPC_PRECACHE) )
04157                 {//a spawner
04158                         Com_Printf( S_COLOR_GREEN"Removing NPC spawner %s named %s\n", player->NPC_type, player->targetname );
04159                         G_FreeEntity( player );
04160                 }
04161                 */
04162                 //rwwFIXMEFIXME: should really do something here.
04163         }
04164 }
04165 
04166 void NPC_PrintScore( gentity_t *ent )
04167 {
04168         Com_Printf( "%s: %d\n", ent->targetname, ent->client->ps.persistant[PERS_SCORE] );
04169 }
04170 
04171 /*
04172 Svcmd_NPC_f
04173 
04174 parse and dispatch bot commands
04175 */
04176 qboolean        showBBoxes = qfalse;
04177 void Cmd_NPC_f( gentity_t *ent ) 
04178 {
04179         char    cmd[1024];
04180 
04181         trap_Argv( 1, cmd, 1024 );
04182 
04183         if ( !cmd[0] ) 
04184         {
04185                 Com_Printf( "Valid NPC commands are:\n" );
04186                 Com_Printf( " spawn [NPC type (from NCPCs.cfg)]\n" );
04187                 Com_Printf( " kill [NPC targetname] or [all(kills all NPCs)] or 'team [teamname]'\n" );
04188                 Com_Printf( " showbounds (draws exact bounding boxes of NPCs)\n" );
04189                 Com_Printf( " score [NPC targetname] (prints number of kills per NPC)\n" );
04190         }
04191         else if ( Q_stricmp( cmd, "spawn" ) == 0 )
04192         {
04193                 NPC_Spawn_f( ent );
04194         }
04195         else if ( Q_stricmp( cmd, "kill" ) == 0 ) 
04196         {
04197                 NPC_Kill_f();
04198         }
04199         else if ( Q_stricmp( cmd, "showbounds" ) == 0 )
04200         {//Toggle on and off
04201                 showBBoxes = showBBoxes ? qfalse : qtrue;
04202         }
04203         else if ( Q_stricmp ( cmd, "score" ) == 0 )
04204         {
04205                 char            cmd2[1024];
04206                 gentity_t *ent = NULL;
04207 
04208                 trap_Argv(2, cmd2, 1024);
04209 
04210                 if ( !cmd2[0] )
04211                 {//Show the score for all NPCs
04212                         int i;
04213 
04214                         Com_Printf( "SCORE LIST:\n" );
04215                         for ( i = 0; i < ENTITYNUM_WORLD; i++ )
04216                         {
04217                                 ent = &g_entities[i];
04218                                 if ( !ent || !ent->client )
04219                                 {
04220                                         continue;
04221                                 }
04222                                 NPC_PrintScore( ent );
04223                         }
04224                 }
04225                 else
04226                 {
04227                         if ( (ent = G_Find( NULL, FOFS(targetname), cmd2 )) != NULL && ent->client )
04228                         {
04229                                 NPC_PrintScore( ent );
04230                         }
04231                         else
04232                         {
04233                                 Com_Printf( "ERROR: NPC score - no such NPC %s\n", cmd2 );
04234                         }
04235                 }
04236         }
04237 }