codemp/game/NPC_stats.c

Go to the documentation of this file.
00001 //NPC_stats.cpp
00002 #include "b_local.h"
00003 #include "b_public.h"
00004 #include "anims.h"
00005 #include "../ghoul2/G2.h"
00006 
00007 extern qboolean NPCsPrecached;
00008 
00009 #include "../namespace_begin.h"
00010 extern qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber );
00011 extern void WP_RemoveSaber( saberInfo_t *sabers, int saberNum );
00012 #include "../namespace_end.h"
00013 
00014 stringID_table_t TeamTable[] =
00015 {
00016         ENUM2STRING(NPCTEAM_FREE),                      // caution, some code checks a team_t via "if (!team_t_varname)" so I guess this should stay as entry 0, great or what? -slc
00017         ENUM2STRING(NPCTEAM_PLAYER),
00018         ENUM2STRING(NPCTEAM_ENEMY),
00019         ENUM2STRING(NPCTEAM_NEUTRAL),   // most droids are team_neutral, there are some exceptions like Probe,Seeker,Interrogator
00020         "",     -1
00021 };
00022 
00023 // this list was made using the model directories, this MUST be in the same order as the CLASS_ enum in teams.h
00024 stringID_table_t ClassTable[] =
00025 {
00026         ENUM2STRING(CLASS_NONE),                                // hopefully this will never be used by an npc), just covering all bases
00027         ENUM2STRING(CLASS_ATST),                                // technically droid...
00028         ENUM2STRING(CLASS_BARTENDER),
00029         ENUM2STRING(CLASS_BESPIN_COP),          
00030         ENUM2STRING(CLASS_CLAW),
00031         ENUM2STRING(CLASS_COMMANDO),
00032         ENUM2STRING(CLASS_DESANN),                      
00033         ENUM2STRING(CLASS_FISH),
00034         ENUM2STRING(CLASS_FLIER2),
00035         ENUM2STRING(CLASS_GALAK),
00036         ENUM2STRING(CLASS_GLIDER),
00037         ENUM2STRING(CLASS_GONK),                                // droid
00038         ENUM2STRING(CLASS_GRAN),
00039         ENUM2STRING(CLASS_HOWLER),
00040 //      ENUM2STRING(CLASS_RANCOR),
00041         ENUM2STRING(CLASS_IMPERIAL),
00042         ENUM2STRING(CLASS_IMPWORKER),
00043         ENUM2STRING(CLASS_INTERROGATOR),                // droid 
00044         ENUM2STRING(CLASS_JAN),                         
00045         ENUM2STRING(CLASS_JEDI),                                
00046         ENUM2STRING(CLASS_KYLE),
00047         ENUM2STRING(CLASS_LANDO),                       
00048         ENUM2STRING(CLASS_LIZARD),
00049         ENUM2STRING(CLASS_LUKE),                                
00050         ENUM2STRING(CLASS_MARK1),                       // droid
00051         ENUM2STRING(CLASS_MARK2),                       // droid
00052         ENUM2STRING(CLASS_GALAKMECH),           // droid
00053         ENUM2STRING(CLASS_MINEMONSTER),
00054         ENUM2STRING(CLASS_MONMOTHA),                    
00055         ENUM2STRING(CLASS_MORGANKATARN),
00056         ENUM2STRING(CLASS_MOUSE),                       // droid
00057         ENUM2STRING(CLASS_MURJJ),
00058         ENUM2STRING(CLASS_PRISONER),
00059         ENUM2STRING(CLASS_PROBE),                       // droid
00060         ENUM2STRING(CLASS_PROTOCOL),                    // droid
00061         ENUM2STRING(CLASS_R2D2),                                // droid
00062         ENUM2STRING(CLASS_R5D2),                                // droid
00063         ENUM2STRING(CLASS_REBEL),
00064         ENUM2STRING(CLASS_REBORN),
00065         ENUM2STRING(CLASS_REELO),
00066         ENUM2STRING(CLASS_REMOTE),
00067         ENUM2STRING(CLASS_RODIAN),
00068         ENUM2STRING(CLASS_SEEKER),                      // droid
00069         ENUM2STRING(CLASS_SENTRY),
00070         ENUM2STRING(CLASS_SHADOWTROOPER),
00071         ENUM2STRING(CLASS_STORMTROOPER),
00072         ENUM2STRING(CLASS_SWAMP),
00073         ENUM2STRING(CLASS_SWAMPTROOPER),
00074         ENUM2STRING(CLASS_TAVION),
00075         ENUM2STRING(CLASS_TRANDOSHAN),
00076         ENUM2STRING(CLASS_UGNAUGHT),
00077         ENUM2STRING(CLASS_JAWA),
00078         ENUM2STRING(CLASS_WEEQUAY),
00079         ENUM2STRING(CLASS_BOBAFETT),
00080         //ENUM2STRING(CLASS_ROCKETTROOPER),
00081         //ENUM2STRING(CLASS_PLAYER),
00082         ENUM2STRING(CLASS_VEHICLE),
00083         ENUM2STRING(CLASS_RANCOR),
00084         ENUM2STRING(CLASS_WAMPA),
00085         "",     -1
00086 };
00087 
00088 stringID_table_t BSTable[] =
00089 {
00090         ENUM2STRING(BS_DEFAULT),//# default behavior for that NPC
00091         ENUM2STRING(BS_ADVANCE_FIGHT),//# Advance to captureGoal and shoot enemies if you can
00092         ENUM2STRING(BS_SLEEP),//# Play awake script when startled by sound
00093         ENUM2STRING(BS_FOLLOW_LEADER),//# Follow your leader and shoot any enemies you come across
00094         ENUM2STRING(BS_JUMP),//# Face navgoal and jump to it.
00095         ENUM2STRING(BS_SEARCH),//# Using current waypoint as a base), search the immediate branches of waypoints for enemies
00096         ENUM2STRING(BS_WANDER),//# Wander down random waypoint paths
00097         ENUM2STRING(BS_NOCLIP),//# Moves through walls), etc.
00098         ENUM2STRING(BS_REMOVE),//# Waits for player to leave PVS then removes itself
00099         ENUM2STRING(BS_CINEMATIC),//# Does nothing but face it's angles and move to a goal if it has one
00100         //the rest are internal only
00101         "",                             -1,
00102 };
00103 
00104 #define stringIDExpand(str, strEnum)    str, strEnum, ENUM2STRING(strEnum)
00105 
00106 stringID_table_t BSETTable[] =
00107 {
00108         ENUM2STRING(BSET_SPAWN),//# script to use when first spawned
00109         ENUM2STRING(BSET_USE),//# script to use when used
00110         ENUM2STRING(BSET_AWAKE),//# script to use when awoken/startled
00111         ENUM2STRING(BSET_ANGER),//# script to use when aquire an enemy
00112         ENUM2STRING(BSET_ATTACK),//# script to run when you attack
00113         ENUM2STRING(BSET_VICTORY),//# script to run when you kill someone
00114         ENUM2STRING(BSET_LOSTENEMY),//# script to run when you can't find your enemy
00115         ENUM2STRING(BSET_PAIN),//# script to use when take pain
00116         ENUM2STRING(BSET_FLEE),//# script to use when take pain below 50% of health
00117         ENUM2STRING(BSET_DEATH),//# script to use when killed
00118         ENUM2STRING(BSET_DELAYED),//# script to run when self->delayScriptTime is reached
00119         ENUM2STRING(BSET_BLOCKED),//# script to run when blocked by a friendly NPC or player
00120         ENUM2STRING(BSET_BUMPED),//# script to run when bumped into a friendly NPC or player (can set bumpRadius)
00121         ENUM2STRING(BSET_STUCK),//# script to run when blocked by a wall
00122         ENUM2STRING(BSET_FFIRE),//# script to run when player shoots their own teammates
00123         ENUM2STRING(BSET_FFDEATH),//# script to run when player kills a teammate
00124         stringIDExpand("", BSET_INVALID),
00125         "",                             -1,
00126 };
00127 
00128 #include "../namespace_begin.h"
00129 extern stringID_table_t WPTable[];
00130 extern stringID_table_t FPTable[];
00131 #include "../namespace_end.h"
00132 
00133 char    *TeamNames[TEAM_NUM_TEAMS] = 
00134 {
00135         "",
00136 //      "starfleet",
00137 //      "borg",
00138 //      "parasite",
00139 //      "scavengers",
00140 //      "klingon",
00141 //      "malon",
00142 //      "hirogen",
00143 //      "imperial",
00144 //      "stasis",
00145 //      "species8472",
00146 //      "dreadnought",
00147 //      "forge",
00148 //      "disguise",
00149 //      "player (not valid)"
00150         "player",
00151         "enemy",
00152         "neutral"
00153 };
00154 
00155 // this list was made using the model directories, this MUST be in the same order as the CLASS_ enum in teams.h
00156 char    *ClassNames[CLASS_NUM_CLASSES] = 
00157 {
00158         "",                             // class none
00159         "atst",
00160         "bartender",
00161         "bespin_cop",
00162         "claw",
00163         "commando",
00164         "desann",
00165         "fish",
00166         "flier2",
00167         "galak",
00168         "glider",
00169         "gonk",                 
00170         "gran",
00171         "howler",
00172         "imperial",
00173         "impworker",
00174         "interrogator",
00175         "jan",
00176         "jedi",
00177         "kyle",
00178         "lando",
00179         "lizard",
00180         "luke",
00181         "mark1",
00182         "mark2",
00183         "galak_mech",
00184         "minemonster",
00185         "monmotha",
00186         "morgankatarn",
00187         "mouse",
00188         "murjj",
00189         "prisoner",
00190         "probe",
00191         "protocol",
00192         "r2d2",
00193         "r5d2",
00194         "rebel",
00195         "reborn",
00196         "reelo",
00197         "remote",
00198         "rodian",
00199         "seeker",
00200         "sentry",
00201         "shadowtrooper",
00202         "stormtrooper",
00203         "swamp",
00204         "swamptrooper",
00205         "tavion",
00206         "trandoshan",
00207         "ugnaught",
00208         "weequay",
00209         "bobafett",
00210         "vehicle",
00211         "rancor",
00212         "wampa",
00213 };
00214 
00215 
00216 /*
00217 NPC_ReactionTime
00218 */
00219 //FIXME use grandom in here
00220 int NPC_ReactionTime ( void ) 
00221 {
00222         return 200 * ( 6 - NPCInfo->stats.reactions );
00223 }
00224 
00225 //
00226 // parse support routines
00227 //
00228 
00229 #include "../namespace_begin.h"
00230 extern qboolean BG_ParseLiteral( const char **data, const char *string );
00231 #include "../namespace_end.h"
00232 
00233 //
00234 // NPC parameters file : scripts/NPCs.cfg
00235 //
00236 #define MAX_NPC_DATA_SIZE 0x20000
00237 char    NPCParms[MAX_NPC_DATA_SIZE];
00238 char    NPCFile[MAX_QPATH];
00239 
00240 /*
00241 team_t TranslateTeamName( const char *name ) 
00242 {
00243         int n;
00244 
00245         for ( n = (NPCTEAM_FREE + 1); n < NPCTEAM_NUM_TEAMS; n++ )
00246         {
00247                 if ( Q_stricmp( TeamNames[n], name ) == 0 )
00248                 {
00249                         return ((team_t) n);
00250                 }
00251         }
00252         
00253         return NPCTEAM_FREE;
00254 }
00255 
00256 class_t TranslateClassName( const char *name ) 
00257 {
00258         int n;
00259 
00260         for ( n = (CLASS_NONE + 1); n < CLASS_NUM_CLASSES; n++ )
00261         {
00262                 if ( Q_stricmp( ClassNames[n], name ) == 0 )
00263                 {
00264                         return ((class_t) n);
00265                 }
00266         }
00267         
00268         return CLASS_NONE;  // I hope this never happens, maybe print a warning
00269 }
00270 */
00271 
00272 /*
00273 static race_t TranslateRaceName( const char *name ) 
00274 {
00275         if ( !Q_stricmp( name, "human" ) ) 
00276         {
00277                 return RACE_HUMAN;
00278         }
00279         return RACE_NONE;
00280 }
00281 */
00282 /*
00283 static rank_t TranslateRankName( const char *name ) 
00284 
00285   Should be used to determine pip bolt-ons
00286 */
00287 static rank_t TranslateRankName( const char *name ) 
00288 {
00289         if ( !Q_stricmp( name, "civilian" ) ) 
00290         {
00291                 return RANK_CIVILIAN;
00292         }
00293 
00294         if ( !Q_stricmp( name, "crewman" ) ) 
00295         {
00296                 return RANK_CREWMAN;
00297         }
00298         
00299         if ( !Q_stricmp( name, "ensign" ) ) 
00300         {
00301                 return RANK_ENSIGN;
00302         }
00303         
00304         if ( !Q_stricmp( name, "ltjg" ) ) 
00305         {
00306                 return RANK_LT_JG;
00307         }
00308         
00309         if ( !Q_stricmp( name, "lt" ) ) 
00310         {
00311                 return RANK_LT;
00312         }
00313         
00314         if ( !Q_stricmp( name, "ltcomm" ) ) 
00315         {
00316                 return RANK_LT_COMM;
00317         }
00318         
00319         if ( !Q_stricmp( name, "commander" ) ) 
00320         {
00321                 return RANK_COMMANDER;
00322         }
00323         
00324         if ( !Q_stricmp( name, "captain" ) ) 
00325         {
00326                 return RANK_CAPTAIN;
00327         }
00328 
00329         return RANK_CIVILIAN;
00330 }
00331 
00332 #include "../namespace_begin.h"
00333 extern saber_colors_t TranslateSaberColor( const char *name );
00334 #include "../namespace_end.h"
00335 
00336 /* static int MethodNameToNumber( const char *name ) {
00337         if ( !Q_stricmp( name, "EXPONENTIAL" ) ) {
00338                 return METHOD_EXPONENTIAL;
00339         }
00340         if ( !Q_stricmp( name, "LINEAR" ) ) {
00341                 return METHOD_LINEAR;
00342         }
00343         if ( !Q_stricmp( name, "LOGRITHMIC" ) ) {
00344                 return METHOD_LOGRITHMIC;
00345         }
00346         if ( !Q_stricmp( name, "ALWAYS" ) ) {
00347                 return METHOD_ALWAYS;
00348         }
00349         if ( !Q_stricmp( name, "NEVER" ) ) {
00350                 return METHOD_NEVER;
00351         }
00352         return -1;
00353 }
00354 
00355 static int ItemNameToNumber( const char *name, int itemType ) {
00356 //      int             n;
00357 
00358         for ( n = 0; n < bg_numItems; n++ ) {
00359                 if ( bg_itemlist[n].type != itemType ) {
00360                         continue;
00361                 }
00362                 if ( Q_stricmp( bg_itemlist[n].classname, name ) == 0 ) {
00363                         return bg_itemlist[n].tag;
00364                 }
00365         }
00366         return -1;
00367 }
00368 */
00369 
00370 //rwwFIXMEFIXME: movetypes
00371 /*
00372 static int MoveTypeNameToEnum( const char *name ) 
00373 {
00374         if(!Q_stricmp("runjump", name))
00375         {
00376                 return MT_RUNJUMP;
00377         }
00378         else if(!Q_stricmp("walk", name))
00379         {
00380                 return MT_WALK;
00381         }
00382         else if(!Q_stricmp("flyswim", name))
00383         {
00384                 return MT_FLYSWIM;
00385         }
00386         else if(!Q_stricmp("static", name))
00387         {
00388                 return MT_STATIC;
00389         }
00390 
00391         return MT_STATIC;
00392 }
00393 */
00394 
00395 //#define CONVENIENT_ANIMATION_FILE_DEBUG_THING
00396 
00397 #ifdef CONVENIENT_ANIMATION_FILE_DEBUG_THING
00398 void SpewDebugStuffToFile(animation_t *anims)
00399 {
00400         char BGPAFtext[40000];
00401         fileHandle_t f;
00402         int i = 0;
00403 
00404         trap_FS_FOpenFile("file_of_debug_stuff_SP.txt", &f, FS_WRITE);
00405 
00406         if (!f)
00407         {
00408                 return;
00409         }
00410 
00411         BGPAFtext[0] = 0;
00412 
00413         while (i < MAX_ANIMATIONS)
00414         {
00415                 strcat(BGPAFtext, va("%i %i\n", i, anims[i].frameLerp));
00416                 i++;
00417         }
00418 
00419         trap_FS_Write(BGPAFtext, strlen(BGPAFtext), f);
00420         trap_FS_FCloseFile(f);
00421 }
00422 #endif
00423 
00424 qboolean G_ParseAnimFileSet( const char *filename, const char *animCFG, int *animFileIndex )
00425 {
00426         *animFileIndex = BG_ParseAnimationFile(filename, NULL, qfalse);
00427         //if it's humanoid we should have it cached and return it, if it is not it will be loaded (unless it's also cached already)
00428 
00429         if (*animFileIndex == -1)
00430         {
00431                 return qfalse;
00432         }
00433 
00434         //I guess this isn't really even needed game-side.
00435         //BG_ParseAnimationSndFile(filename, *animFileIndex);
00436         return qtrue;
00437 }
00438 
00439 void NPC_PrecacheAnimationCFG( const char *NPC_type )
00440 {
00441 #if 0 //rwwFIXMEFIXME: Actually precache stuff here.
00442         char    filename[MAX_QPATH];
00443         const char      *token;
00444         const char      *value;
00445         const char      *p;
00446         int             junk;
00447 
00448         if ( !Q_stricmp( "random", NPC_type ) )
00449         {//sorry, can't precache a random just yet
00450                 return;
00451         }
00452 
00453         p = NPCParms;
00454         COM_BeginParseSession(NPCFile);
00455 
00456         // look for the right NPC
00457         while ( p ) 
00458         {
00459                 token = COM_ParseExt( &p, qtrue );
00460                 if ( token[0] == 0 )
00461                         return;
00462 
00463                 if ( !Q_stricmp( token, NPC_type ) ) 
00464                 {
00465                         break;
00466                 }
00467 
00468                 SkipBracedSection( &p );
00469         }
00470 
00471         if ( !p ) 
00472         {
00473                 return;
00474         }
00475 
00476         if ( BG_ParseLiteral( &p, "{" ) ) 
00477         {
00478                 return;
00479         }
00480 
00481         // parse the NPC info block
00482         while ( 1 ) 
00483         {
00484                 token = COM_ParseExt( &p, qtrue );
00485                 if ( !token[0] ) 
00486                 {
00487                         Com_Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", NPC_type );
00488                         return;
00489                 }
00490 
00491                 if ( !Q_stricmp( token, "}" ) ) 
00492                 {
00493                         break;
00494                 }
00495 
00496                 // legsmodel
00497                 if ( !Q_stricmp( token, "legsmodel" ) ) 
00498                 {
00499                         if ( COM_ParseString( &p, &value ) ) 
00500                         {
00501                                 continue;
00502                         }
00503                         //must copy data out of this pointer into a different part of memory because the funcs we're about to call will call COM_ParseExt
00504                         Q_strncpyz( filename, value, sizeof( filename ) );
00505                         G_ParseAnimFileSet( filename, filename, &junk );
00506                         return;
00507                 }
00508 
00509                 // playerModel
00510                 if ( !Q_stricmp( token, "playerModel" ) ) 
00511                 {
00512                         if ( COM_ParseString( &p, &value ) ) 
00513                         {
00514                                 continue;
00515                         }
00516                         /*
00517                         char    animName[MAX_QPATH];
00518                         char    *GLAName;
00519                         char    *slash = NULL;
00520                         char    *strippedName;
00521                         
00522                         int handle = gi.G2API_PrecacheGhoul2Model( va( "models/players/%s/model.glm", value ) );
00523                         if ( handle > 0 )//FIXME: isn't 0 a valid handle?
00524                         {
00525                                 GLAName = gi.G2API_GetAnimFileNameIndex( handle );
00526                                 if ( GLAName )
00527                                 {
00528                                         Q_strncpyz( animName, GLAName, sizeof( animName ), qtrue );
00529                                         slash = strrchr( animName, '/' );
00530                                         if ( slash )
00531                                         {
00532                                                 *slash = 0;
00533                                         }
00534                                         strippedName = COM_SkipPath( animName );
00535 
00536                                         //must copy data out of this pointer into a different part of memory because the funcs we're about to call will call COM_ParseExt
00537                                         Q_strncpyz( filename, value, sizeof( filename ), qtrue );
00538                                         G_ParseAnimFileSet( value, strippedName, &junk );//qfalse );
00539                                         //FIXME: still not precaching the animsounds.cfg?
00540                                         return;
00541                                 }
00542                         }
00543                         */
00544                         //rwwFIXMEFIXME: Do this properly.
00545                 }
00546         }
00547 #endif
00548 }
00549 
00550 extern int NPC_WeaponsForTeam( team_t team, int spawnflags, const char *NPC_type );
00551 void NPC_PrecacheWeapons( team_t playerTeam, int spawnflags, char *NPCtype )
00552 {
00553         int weapons = NPC_WeaponsForTeam( playerTeam, spawnflags, NPCtype );
00554         int curWeap;
00555 
00556         for ( curWeap = WP_SABER; curWeap < WP_NUM_WEAPONS; curWeap++ )
00557         {
00558                 if (weapons & (1 << curWeap))
00559                 {
00560                         RegisterItem(BG_FindItemForWeapon((weapon_t)curWeap));
00561                 }
00562         }
00563 
00564 #if 0 //rwwFIXMEFIXME: actually precache weapons here
00565         int weapons = NPC_WeaponsForTeam( playerTeam, spawnflags, NPCtype );
00566         gitem_t *item;
00567         for ( int curWeap = WP_SABER; curWeap < WP_NUM_WEAPONS; curWeap++ )
00568         {
00569                 if ( (weapons & ( 1 << curWeap )) )
00570                 {
00571                         item = FindItemForWeapon( ((weapon_t)(curWeap)) );      //precache the weapon
00572                         CG_RegisterItemSounds( (item-bg_itemlist) );
00573                         CG_RegisterItemVisuals( (item-bg_itemlist) );
00574                         //precache the in-hand/in-world ghoul2 weapon model
00575 
00576                         char weaponModel[64];
00577                         
00578                         strcpy (weaponModel, weaponData[curWeap].weaponMdl);    
00579                         if (char *spot = strstr(weaponModel, ".md3") ) {
00580                                 *spot = 0;
00581                                 spot = strstr(weaponModel, "_w");//i'm using the in view weapon array instead of scanning the item list, so put the _w back on
00582                                 if (!spot) {
00583                                         strcat (weaponModel, "_w");
00584                                 }
00585                                 strcat (weaponModel, ".glm");   //and change to ghoul2
00586                         }
00587                         gi.G2API_PrecacheGhoul2Model( weaponModel ); // correct way is item->world_model
00588                 }
00589         }
00590 #endif
00591 }
00592 
00593 /*
00594 void NPC_Precache ( char *NPCName )
00595 
00596 Precaches NPC skins, tgas and md3s.
00597 
00598 */
00599 void NPC_Precache ( gentity_t *spawner )
00600 {
00601         npcteam_t                       playerTeam = NPCTEAM_FREE;
00602         const char      *token;
00603         const char      *value;
00604         const char      *p;
00605         char    *patch;
00606         char    sound[MAX_QPATH];
00607         qboolean        md3Model = qfalse;
00608         char    playerModel[MAX_QPATH];
00609         char    customSkin[MAX_QPATH];
00610 
00611         if ( !Q_stricmp( "random", spawner->NPC_type ) )
00612         {//sorry, can't precache a random just yet
00613                 return;
00614         }
00615         strcpy(customSkin,"default");
00616 
00617         p = NPCParms;
00618         COM_BeginParseSession(NPCFile);
00619 
00620         // look for the right NPC
00621         while ( p ) 
00622         {
00623                 token = COM_ParseExt( &p, qtrue );
00624                 if ( token[0] == 0 )
00625                         return;
00626 
00627                 if ( !Q_stricmp( token, spawner->NPC_type ) ) 
00628                 {
00629                         break;
00630                 }
00631 
00632                 SkipBracedSection( &p );
00633         }
00634 
00635         if ( !p ) 
00636         {
00637                 return;
00638         }
00639 
00640         if ( BG_ParseLiteral( &p, "{" ) ) 
00641         {
00642                 return;
00643         }
00644 
00645         // parse the NPC info block
00646         while ( 1 ) 
00647         {
00648                 token = COM_ParseExt( &p, qtrue );
00649                 if ( !token[0] ) 
00650                 {
00651                         Com_Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", spawner->NPC_type );
00652                         return;
00653                 }
00654 
00655                 if ( !Q_stricmp( token, "}" ) ) 
00656                 {
00657                         break;
00658                 }
00659 
00660                 // headmodel
00661                 if ( !Q_stricmp( token, "headmodel" ) ) 
00662                 {
00663                         if ( COM_ParseString( &p, &value ) ) 
00664                         {
00665                                 continue;
00666                         }
00667 
00668                         if(!Q_stricmp("none", value))
00669                         {
00670                         }
00671                         else
00672                         {
00673                                 //Q_strncpyz( ri.headModelName, value, sizeof(ri.headModelName), qtrue);
00674                         }
00675                         md3Model = qtrue;
00676                         continue;
00677                 }
00678                 
00679                 // torsomodel
00680                 if ( !Q_stricmp( token, "torsomodel" ) ) 
00681                 {
00682                         if ( COM_ParseString( &p, &value ) ) 
00683                         {
00684                                 continue;
00685                         }
00686 
00687                         if(!Q_stricmp("none", value))
00688                         {
00689                         }
00690                         else
00691                         {
00692                                 //Q_strncpyz( ri.torsoModelName, value, sizeof(ri.torsoModelName), qtrue);
00693                         }
00694                         md3Model = qtrue;
00695                         continue;
00696                 }
00697 
00698                 // legsmodel
00699                 if ( !Q_stricmp( token, "legsmodel" ) ) 
00700                 {
00701                         if ( COM_ParseString( &p, &value ) ) 
00702                         {
00703                                 continue;
00704                         }
00705                         //Q_strncpyz( ri.legsModelName, value, sizeof(ri.legsModelName), qtrue);                        
00706                         md3Model = qtrue;
00707                         continue;
00708                 }
00709 
00710                 // playerModel
00711                 if ( !Q_stricmp( token, "playerModel" ) ) 
00712                 {
00713                         if ( COM_ParseString( &p, &value ) ) 
00714                         {
00715                                 continue;
00716                         }
00717                         Q_strncpyz( playerModel, value, sizeof(playerModel));                   
00718                         md3Model = qfalse;
00719                         continue;
00720                 }
00721 
00722                 // customSkin
00723                 if ( !Q_stricmp( token, "customSkin" ) ) 
00724                 {
00725                         if ( COM_ParseString( &p, &value ) ) 
00726                         {
00727                                 continue;
00728                         }
00729                         Q_strncpyz( customSkin, value, sizeof(customSkin));                     
00730                         continue;
00731                 }
00732 
00733                 // playerTeam
00734                 if ( !Q_stricmp( token, "playerTeam" ) ) 
00735                 {
00736                         char tk[4096]; //rww - hackilicious!
00737 
00738                         if ( COM_ParseString( &p, &value ) ) 
00739                         {
00740                                 continue;
00741                         }
00742                         //playerTeam = TranslateTeamName(value);
00743                         Com_sprintf(tk, sizeof(tk), "NPC%s", token);
00744                         playerTeam = (team_t)GetIDForString( TeamTable, tk );
00745                         continue;
00746                 }
00747 
00748         
00749                 // snd
00750                 if ( !Q_stricmp( token, "snd" ) ) {
00751                         if ( COM_ParseString( &p, &value ) ) {
00752                                 continue;
00753                         }
00754                         if ( !(spawner->r.svFlags&SVF_NO_BASIC_SOUNDS) )
00755                         {
00756                                 //FIXME: store this in some sound field or parse in the soundTable like the animTable...
00757                                 Q_strncpyz( sound, value, sizeof( sound ) );
00758                                 patch = strstr( sound, "/" );
00759                                 if ( patch ) 
00760                                 {
00761                                         *patch = 0;
00762                                 }
00763                                 spawner->s.csSounds_Std = G_SoundIndex( va("*$%s", sound) );
00764                         }
00765                         continue;
00766                 }
00767 
00768                 // sndcombat
00769                 if ( !Q_stricmp( token, "sndcombat" ) ) {
00770                         if ( COM_ParseString( &p, &value ) ) {
00771                                 continue;
00772                         }
00773                         if ( !(spawner->r.svFlags&SVF_NO_COMBAT_SOUNDS) )
00774                         {
00775                                 //FIXME: store this in some sound field or parse in the soundTable like the animTable...
00776                                 Q_strncpyz( sound, value, sizeof( sound ) );
00777                                 patch = strstr( sound, "/" );
00778                                 if ( patch ) 
00779                                 {
00780                                         *patch = 0;
00781                                 }
00782                                 spawner->s.csSounds_Combat = G_SoundIndex( va("*$%s", sound) );
00783                         }
00784                         continue;
00785                 }
00786                 
00787                 // sndextra
00788                 if ( !Q_stricmp( token, "sndextra" ) ) {
00789                         if ( COM_ParseString( &p, &value ) ) {
00790                                 continue;
00791                         }
00792                         if ( !(spawner->r.svFlags&SVF_NO_EXTRA_SOUNDS) )
00793                         {
00794                                 //FIXME: store this in some sound field or parse in the soundTable like the animTable...
00795                                 Q_strncpyz( sound, value, sizeof( sound ) );
00796                                 patch = strstr( sound, "/" );
00797                                 if ( patch ) 
00798                                 {
00799                                         *patch = 0;
00800                                 }
00801                                 spawner->s.csSounds_Extra = G_SoundIndex( va("*$%s", sound) );
00802                         }
00803                         continue;
00804                 }
00805 
00806                 // sndjedi
00807                 if ( !Q_stricmp( token, "sndjedi" ) ) {
00808                         if ( COM_ParseString( &p, &value ) ) {
00809                                 continue;
00810                         }
00811                         if ( !(spawner->r.svFlags&SVF_NO_EXTRA_SOUNDS) )
00812                         {
00813                                 //FIXME: store this in some sound field or parse in the soundTable like the animTable...
00814                                 Q_strncpyz( sound, value, sizeof( sound ) );
00815                                 patch = strstr( sound, "/" );
00816                                 if ( patch ) 
00817                                 {
00818                                         *patch = 0;
00819                                 }
00820                                 spawner->s.csSounds_Jedi = G_SoundIndex( va("*$%s", sound) );
00821                         }
00822                         continue;
00823                 }
00824 
00825                 if (!Q_stricmp(token, "weapon"))
00826                 {
00827                         int curWeap;
00828 
00829                         if (COM_ParseString(&p, &value))
00830                         {
00831                                 continue;
00832                         }
00833 
00834                         curWeap = GetIDForString( WPTable, value );
00835 
00836                         if (curWeap > WP_NONE && curWeap < WP_NUM_WEAPONS)
00837                         {
00838                                 RegisterItem(BG_FindItemForWeapon((weapon_t)curWeap));
00839                         }
00840                         continue;
00841                 }
00842         }
00843 
00844         // If we're not a vehicle, then an error here would be valid...
00845         if ( !spawner->client || spawner->client->NPC_class != CLASS_VEHICLE )
00846         {
00847                 if ( md3Model )
00848                 {
00849                         Com_Printf("MD3 model using NPCs are not supported in MP\n");
00850                 }
00851                 else
00852                 { //if we have a model/skin then index them so they'll be registered immediately
00853                         //when the client gets a configstring update.
00854                         char modelName[MAX_QPATH];
00855 
00856                         Com_sprintf(modelName, sizeof(modelName), "models/players/%s/model.glm", playerModel);
00857                         if (customSkin[0])
00858                         { //append it after a *
00859                                 strcat( modelName, va("*%s", customSkin) );
00860                         }
00861 
00862                         G_ModelIndex(modelName);
00863                 }
00864         }
00865 
00866         //precache this NPC's possible weapons
00867         NPC_PrecacheWeapons( playerTeam, spawner->spawnflags, spawner->NPC_type );
00868 
00869 //      CG_RegisterNPCCustomSounds( &ci );
00870 //      CG_RegisterNPCEffects( playerTeam );
00871         //rwwFIXMEFIXME: same
00872         //FIXME: Look for a "sounds" directory and precache death, pain, alert sounds
00873 }
00874 
00875 #if 0
00876 void NPC_BuildRandom( gentity_t *NPC )
00877 {
00878         int     sex, color, head;
00879 
00880         sex = Q_irand(0, 2);
00881         color = Q_irand(0, 2);
00882         switch( sex )
00883         {
00884         case 0://female
00885                 head = Q_irand(0, 2);
00886                 switch( head )
00887                 {
00888                 default:
00889                 case 0:
00890                         Q_strncpyz( NPC->client->renderInfo.headModelName, "garren", sizeof(NPC->client->renderInfo.headModelName), qtrue );
00891                         break;
00892                 case 1:
00893                         Q_strncpyz( NPC->client->renderInfo.headModelName, "garren/salma", sizeof(NPC->client->renderInfo.headModelName), qtrue );
00894                         break;
00895                 case 2:
00896                         Q_strncpyz( NPC->client->renderInfo.headModelName, "garren/mackey", sizeof(NPC->client->renderInfo.headModelName), qtrue );
00897                         color = Q_irand(3, 5);//torso needs to be afam
00898                         break;
00899                 }
00900                 switch( color )
00901                 {
00902                 default:
00903                 case 0:
00904                         Q_strncpyz( NPC->client->renderInfo.torsoModelName, "crewfemale/gold", sizeof(NPC->client->renderInfo.torsoModelName), qtrue );
00905                         break;
00906                 case 1:
00907                         Q_strncpyz( NPC->client->renderInfo.torsoModelName, "crewfemale", sizeof(NPC->client->renderInfo.torsoModelName), qtrue );
00908                         break;
00909                 case 2:
00910                         Q_strncpyz( NPC->client->renderInfo.torsoModelName, "crewfemale/blue", sizeof(NPC->client->renderInfo.torsoModelName), qtrue );
00911                         break;
00912                 case 3:
00913                         Q_strncpyz( NPC->client->renderInfo.torsoModelName, "crewfemale/aframG", sizeof(NPC->client->renderInfo.torsoModelName), qtrue );
00914                         break;
00915                 case 4:
00916                         Q_strncpyz( NPC->client->renderInfo.torsoModelName, "crewfemale/aframR", sizeof(NPC->client->renderInfo.torsoModelName), qtrue );
00917                         break;
00918                 case 5:
00919                         Q_strncpyz( NPC->client->renderInfo.torsoModelName, "crewfemale/aframB", sizeof(NPC->client->renderInfo.torsoModelName), qtrue );
00920                         break;
00921                 }
00922                 Q_strncpyz( NPC->client->renderInfo.legsModelName, "crewfemale", sizeof(NPC->client->renderInfo.legsModelName), qtrue );
00923                 break;
00924         default:
00925         case 1://male
00926         case 2://male
00927                 head = Q_irand(0, 4);
00928                 switch( head )
00929                 {
00930                 default:
00931                 case 0:
00932                         Q_strncpyz( NPC->client->renderInfo.headModelName, "chakotay/nelson", sizeof(NPC->client->renderInfo.headModelName), qtrue );
00933                         break;
00934                 case 1:
00935                         Q_strncpyz( NPC->client->renderInfo.headModelName, "paris/chase", sizeof(NPC->client->renderInfo.headModelName), qtrue );
00936                         break;
00937                 case 2:
00938                         Q_strncpyz( NPC->client->renderInfo.headModelName, "doctor/pasty", sizeof(NPC->client->renderInfo.headModelName), qtrue );
00939                         break;
00940                 case 3:
00941                         Q_strncpyz( NPC->client->renderInfo.headModelName, "kim/durk", sizeof(NPC->client->renderInfo.headModelName), qtrue );
00942                         break;
00943                 case 4:
00944                         Q_strncpyz( NPC->client->renderInfo.headModelName, "paris/kray", sizeof(NPC->client->renderInfo.headModelName), qtrue );
00945                         break;
00946                 }
00947                 switch( color )
00948                 {
00949                 default:
00950                 case 0:
00951                         Q_strncpyz( NPC->client->renderInfo.torsoModelName, "crewthin/red", sizeof(NPC->client->renderInfo.torsoModelName), qtrue );
00952                         break;
00953                 case 1:
00954                         Q_strncpyz( NPC->client->renderInfo.torsoModelName, "crewthin", sizeof(NPC->client->renderInfo.torsoModelName), qtrue );
00955                         break;
00956                 case 2:
00957                         Q_strncpyz( NPC->client->renderInfo.torsoModelName, "crewthin/blue", sizeof(NPC->client->renderInfo.torsoModelName), qtrue );
00958                         break;
00959                         //NOTE: 3 - 5 should be red, gold & blue, afram hands
00960                 }
00961                 Q_strncpyz( NPC->client->renderInfo.legsModelName, "crewthin", sizeof(NPC->client->renderInfo.legsModelName), qtrue );
00962                 break;
00963         }
00964 
00965         NPC->s.modelScale[0] = NPC->s.modelScale[1] = NPC->s.modelScale[2] = Q_irand(87, 102)/100.0f;
00966 //      NPC->client->race = RACE_HUMAN;
00967         NPC->NPC->rank = RANK_CREWMAN;
00968         NPC->client->playerTeam = NPC->s.teamowner = TEAM_PLAYER;
00969         NPC->client->clientInfo.customBasicSoundDir = "kyle";//FIXME: generic default?
00970 }
00971 #endif
00972 
00973 extern void SetupGameGhoul2Model(gentity_t *ent, char *modelname, char *skinName);
00974 qboolean NPC_ParseParms( const char *NPCName, gentity_t *NPC ) 
00975 {
00976         const char      *token;
00977         const char      *value;
00978         const char      *p;
00979         int             n;
00980         float   f;
00981         char    *patch;
00982         char    sound[MAX_QPATH];
00983         char    playerModel[MAX_QPATH];
00984         char    customSkin[MAX_QPATH];
00985         renderInfo_t    *ri = &NPC->client->renderInfo;
00986         gNPCstats_t             *stats = NULL;
00987         qboolean        md3Model = qtrue;
00988         char    surfOff[1024];
00989         char    surfOn[1024];
00990         qboolean parsingPlayer = qfalse;
00991         vec3_t playerMins;
00992         vec3_t playerMaxs;
00993         int npcSaber1 = 0;
00994         int npcSaber2 = 0;
00995 
00996         VectorSet(playerMins, -15, -15, DEFAULT_MINS_2);
00997         VectorSet(playerMaxs, 15, 15, DEFAULT_MAXS_2);
00998 
00999         strcpy(customSkin,"default");
01000         if ( !NPCName || !NPCName[0]) 
01001         {
01002                 NPCName = "Player";
01003         }
01004 
01005         if ( !NPC->s.number && NPC->client != NULL )
01006         {//player, only want certain data
01007                 parsingPlayer = qtrue;
01008         }
01009 
01010         if ( NPC->NPC )
01011         {
01012                 stats = &NPC->NPC->stats;
01013 /*
01014         NPC->NPC->allWeaponOrder[0]     = WP_BRYAR_PISTOL;
01015         NPC->NPC->allWeaponOrder[1]     = WP_SABER;
01016         NPC->NPC->allWeaponOrder[2]     = WP_IMOD;
01017         NPC->NPC->allWeaponOrder[3]     = WP_SCAVENGER_RIFLE;
01018         NPC->NPC->allWeaponOrder[4]     = WP_TRICORDER;
01019         NPC->NPC->allWeaponOrder[6]     = WP_NONE;
01020         NPC->NPC->allWeaponOrder[6]     = WP_NONE;
01021         NPC->NPC->allWeaponOrder[7]     = WP_NONE;
01022 */
01023                 // fill in defaults
01024                 stats->aggression       = 3;
01025                 stats->aim                      = 3;
01026                 stats->earshot          = 1024;
01027                 stats->evasion          = 3;
01028                 stats->hfov                     = 90;
01029                 stats->intelligence     = 3;
01030                 stats->move                     = 3;
01031                 stats->reactions        = 3;
01032                 stats->vfov                     = 60;
01033                 stats->vigilance        = 0.1f;
01034                 stats->visrange         = 1024;
01035 
01036                 stats->health           = 0;
01037 
01038                 stats->yawSpeed         = 90;
01039                 stats->walkSpeed        = 90;
01040                 stats->runSpeed         = 300;
01041                 stats->acceleration     = 15;//Increase/descrease speed this much per frame (20fps)
01042         }
01043         else
01044         {
01045                 stats = NULL;
01046         }
01047 
01048         //Set defaults
01049         //FIXME: should probably put default torso and head models, but what about enemies
01050         //that don't have any- like Stasis?
01051         //Q_strncpyz( ri->headModelName,        DEFAULT_HEADMODEL,  sizeof(ri->headModelName),  qtrue);
01052         //Q_strncpyz( ri->torsoModelName, DEFAULT_TORSOMODEL, sizeof(ri->torsoModelName),       qtrue);
01053         //Q_strncpyz( ri->legsModelName,        DEFAULT_LEGSMODEL,  sizeof(ri->legsModelName),  qtrue);
01054         //FIXME: should we have one for weapon too?
01055         memset( (char *)surfOff, 0, sizeof(surfOff) );
01056         memset( (char *)surfOn, 0, sizeof(surfOn) );
01057         
01058         /*
01059         ri->headYawRangeLeft = 50;
01060         ri->headYawRangeRight = 50;
01061         ri->headPitchRangeUp = 40;
01062         ri->headPitchRangeDown = 50;
01063         ri->torsoYawRangeLeft = 60;
01064         ri->torsoYawRangeRight = 60;
01065         ri->torsoPitchRangeUp = 30;
01066         ri->torsoPitchRangeDown = 70;
01067         */
01068 
01069         ri->headYawRangeLeft = 80;
01070         ri->headYawRangeRight = 80;
01071         ri->headPitchRangeUp = 45;
01072         ri->headPitchRangeDown = 45;
01073         ri->torsoYawRangeLeft = 60;
01074         ri->torsoYawRangeRight = 60;
01075         ri->torsoPitchRangeUp = 30;
01076         ri->torsoPitchRangeDown = 50;
01077 
01078         VectorCopy(playerMins, NPC->r.mins);
01079         VectorCopy(playerMaxs, NPC->r.maxs);
01080         NPC->client->ps.crouchheight = CROUCH_MAXS_2;
01081         NPC->client->ps.standheight = DEFAULT_MAXS_2;
01082 
01083         //rwwFIXMEFIXME: ...
01084         /*
01085         NPC->client->moveType           = MT_RUNJUMP;
01086 
01087         NPC->client->dismemberProbHead = 100;
01088         NPC->client->dismemberProbArms = 100;
01089         NPC->client->dismemberProbHands = 100;
01090         NPC->client->dismemberProbWaist = 100;
01091         NPC->client->dismemberProbLegs = 100;
01092 
01093         NPC->s.modelScale[0] = NPC->s.modelScale[1] = NPC->s.modelScale[2] = 1.0f;
01094         */
01095 
01096         NPC->client->ps.customRGBA[0]=255;
01097         NPC->client->ps.customRGBA[1]=255;
01098         NPC->client->ps.customRGBA[2]=255;
01099         NPC->client->ps.customRGBA[3]=255;
01100 
01101         if ( !Q_stricmp( "random", NPCName ) )
01102         {//Randomly assemble a starfleet guy
01103                 //NPC_BuildRandom( NPC );
01104                 Com_Printf("RANDOM NPC NOT SUPPORTED IN MP\n");
01105                 return qfalse;
01106         }
01107         else
01108         {
01109                 int fp;
01110 
01111                 p = NPCParms;
01112                 COM_BeginParseSession(NPCFile);
01113 
01114                 // look for the right NPC
01115                 while ( p ) 
01116                 {
01117                         token = COM_ParseExt( &p, qtrue );
01118                         if ( token[0] == 0 )
01119                         {
01120                                 return qfalse;
01121                         }
01122 
01123                         if ( !Q_stricmp( token, NPCName ) ) 
01124                         {
01125                                 break;
01126                         }
01127 
01128                         SkipBracedSection( &p );
01129                 }
01130                 if ( !p ) 
01131                 {
01132                         return qfalse;
01133                 }
01134 
01135                 if ( BG_ParseLiteral( &p, "{" ) ) 
01136                 {
01137                         return qfalse;
01138                 }
01139                         
01140                 // parse the NPC info block
01141                 while ( 1 ) 
01142                 {
01143                         token = COM_ParseExt( &p, qtrue );
01144                         if ( !token[0] ) 
01145                         {
01146                                 Com_Printf( S_COLOR_RED"ERROR: unexpected EOF while parsing '%s'\n", NPCName );
01147                                 return qfalse;
01148                         }
01149 
01150                         if ( !Q_stricmp( token, "}" ) ) 
01151                         {
01152                                 break;
01153                         }
01154         //===MODEL PROPERTIES===========================================================
01155                         // custom color
01156                         if ( !Q_stricmp( token, "customRGBA" ) ) 
01157                         {
01158                                 if ( COM_ParseString( &p, &value ) ) 
01159                                 {
01160                                         continue;
01161                                 }
01162                                 if ( !Q_stricmp( value, "random") )
01163                                 {
01164                                         NPC->client->ps.customRGBA[0]=Q_irand(0,255);
01165                                         NPC->client->ps.customRGBA[1]=Q_irand(0,255);
01166                                         NPC->client->ps.customRGBA[2]=Q_irand(0,255);
01167                                         NPC->client->ps.customRGBA[3]=255;
01168                                 } 
01169                                 else 
01170                                 {
01171                                         NPC->client->ps.customRGBA[0]=atoi(value);
01172                                         
01173                                         if ( COM_ParseInt( &p, &n ) ) 
01174                                         {
01175                                                 continue;
01176                                         }
01177                                         NPC->client->ps.customRGBA[1]=n;
01178                                         
01179                                         if ( COM_ParseInt( &p, &n ) ) 
01180                                         {
01181                                                 continue;
01182                                         }
01183                                         NPC->client->ps.customRGBA[2]=n;
01184                                         
01185                                         if ( COM_ParseInt( &p, &n ) ) 
01186                                         {
01187                                                 continue;
01188                                         }
01189                                         NPC->client->ps.customRGBA[3]=n;
01190                                 }
01191                                 continue;
01192                         }
01193 
01194                         // headmodel
01195                         if ( !Q_stricmp( token, "headmodel" ) ) 
01196                         {
01197                                 if ( COM_ParseString( &p, &value ) ) 
01198                                 {
01199                                         continue;
01200                                 }
01201 
01202                                 if(!Q_stricmp("none", value))
01203                                 {
01204                                         //Zero the head clamp range so the torso & legs don't lag behind
01205                                         ri->headYawRangeLeft = 
01206                                         ri->headYawRangeRight = 
01207                                         ri->headPitchRangeUp = 
01208                                         ri->headPitchRangeDown = 0;
01209                                 }
01210                                 continue;
01211                         }
01212                         
01213                         // torsomodel
01214                         if ( !Q_stricmp( token, "torsomodel" ) ) 
01215                         {
01216                                 if ( COM_ParseString( &p, &value ) ) 
01217                                 {
01218                                         continue;
01219                                 }
01220 
01221                                 if(!Q_stricmp("none", value))
01222                                 {
01223                                         //Zero the torso clamp range so the legs don't lag behind
01224                                         ri->torsoYawRangeLeft = 
01225                                         ri->torsoYawRangeRight = 
01226                                         ri->torsoPitchRangeUp = 
01227                                         ri->torsoPitchRangeDown = 0;
01228                                 }
01229                                 continue;
01230                         }
01231 
01232                         // legsmodel
01233                         if ( !Q_stricmp( token, "legsmodel" ) ) 
01234                         {
01235                                 if ( COM_ParseString( &p, &value ) ) 
01236                                 {
01237                                         continue;
01238                                 }
01239                                 /*
01240                                 Q_strncpyz( ri->legsModelName, value, sizeof(ri->legsModelName), qtrue);                        
01241                                 //Need to do this here to get the right index
01242                                 G_ParseAnimFileSet( ri->legsModelName, ri->legsModelName, &ci->animFileIndex );
01243                                 */
01244                                 continue;
01245                         }
01246 
01247                         // playerModel
01248                         if ( !Q_stricmp( token, "playerModel" ) ) 
01249                         {
01250                                 if ( COM_ParseString( &p, &value ) ) 
01251                                 {
01252                                         continue;
01253                                 }
01254                                 Q_strncpyz( playerModel, value, sizeof(playerModel));                   
01255                                 md3Model = qfalse;
01256                                 continue;
01257                         }
01258                         
01259                         // customSkin
01260                         if ( !Q_stricmp( token, "customSkin" ) ) 
01261                         {
01262                                 if ( COM_ParseString( &p, &value ) ) 
01263                                 {
01264                                         continue;
01265                                 }
01266                                 Q_strncpyz( customSkin, value, sizeof(customSkin));                     
01267                                 continue;
01268                         }
01269 
01270                         // surfOff
01271                         if ( !Q_stricmp( token, "surfOff" ) ) 
01272                         {
01273                                 if ( COM_ParseString( &p, &value ) ) 
01274                                 {
01275                                         continue;
01276                                 }
01277                                 if ( surfOff[0] )
01278                                 {
01279                                         Q_strcat( (char *)surfOff, sizeof(surfOff), "," );
01280                                         Q_strcat( (char *)surfOff, sizeof(surfOff), value );
01281                                 }
01282                                 else
01283                                 {
01284                                         Q_strncpyz( surfOff, value, sizeof(surfOff));
01285                                 }
01286                                 continue;
01287                         }
01288                         
01289                         // surfOn
01290                         if ( !Q_stricmp( token, "surfOn" ) ) 
01291                         {
01292                                 if ( COM_ParseString( &p, &value ) ) 
01293                                 {
01294                                         continue;
01295                                 }
01296                                 if ( surfOn[0] )
01297                                 {
01298                                         Q_strcat( (char *)surfOn, sizeof(surfOn), "," );
01299                                         Q_strcat( (char *)surfOn, sizeof(surfOn), value );
01300                                 }
01301                                 else
01302                                 {
01303                                         Q_strncpyz( surfOn, value, sizeof(surfOn));
01304                                 }
01305                                 continue;
01306                         }
01307                         
01308                         //headYawRangeLeft
01309                         if ( !Q_stricmp( token, "headYawRangeLeft" ) ) 
01310                         {
01311                                 if ( COM_ParseInt( &p, &n ) ) 
01312                                 {
01313                                         SkipRestOfLine( &p );
01314                                         continue;
01315                                 }
01316                                 if ( n < 0 ) 
01317                                 {
01318                                         Com_Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
01319                                         continue;
01320                                 }
01321                                 ri->headYawRangeLeft = n;
01322                                 continue;
01323                         }
01324 
01325                         //headYawRangeRight
01326                         if ( !Q_stricmp( token, "headYawRangeRight" ) ) 
01327                         {
01328                                 if ( COM_ParseInt( &p, &n ) ) 
01329                                 {
01330                                         SkipRestOfLine( &p );
01331                                         continue;
01332                                 }
01333                                 if ( n < 0 ) 
01334                                 {
01335                                         Com_Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
01336                                         continue;
01337                                 }
01338                                 ri->headYawRangeRight = n;
01339                                 continue;
01340                         }
01341 
01342                         //headPitchRangeUp
01343                         if ( !Q_stricmp( token, "headPitchRangeUp" ) ) 
01344                         {
01345                                 if ( COM_ParseInt( &p, &n ) ) 
01346                                 {
01347                                         SkipRestOfLine( &p );
01348                                         continue;
01349                                 }
01350                                 if ( n < 0 ) 
01351                                 {
01352                                         Com_Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
01353                                         continue;
01354                                 }
01355                                 ri->headPitchRangeUp = n;
01356                                 continue;
01357                         }
01358                         
01359                         //headPitchRangeDown
01360                         if ( !Q_stricmp( token, "headPitchRangeDown" ) ) 
01361                         {
01362                                 if ( COM_ParseInt( &p, &n ) ) 
01363                                 {
01364                                         SkipRestOfLine( &p );
01365                                         continue;
01366                                 }
01367                                 if ( n < 0 ) 
01368                                 {
01369                                         Com_Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
01370                                         continue;
01371                                 }
01372                                 ri->headPitchRangeDown = n;
01373                                 continue;
01374                         }
01375 
01376                         //torsoYawRangeLeft
01377                         if ( !Q_stricmp( token, "torsoYawRangeLeft" ) ) 
01378                         {
01379                                 if ( COM_ParseInt( &p, &n ) ) 
01380                                 {
01381                                         SkipRestOfLine( &p );
01382                                         continue;
01383                                 }
01384                                 if ( n < 0 ) 
01385                                 {
01386                                         Com_Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
01387                                         continue;
01388                                 }
01389                                 ri->torsoYawRangeLeft = n;
01390                                 continue;
01391                         }
01392 
01393                         //torsoYawRangeRight
01394                         if ( !Q_stricmp( token, "torsoYawRangeRight" ) ) 
01395                         {
01396                                 if ( COM_ParseInt( &p, &n ) ) 
01397                                 {
01398                                         SkipRestOfLine( &p );
01399                                         continue;
01400                                 }
01401                                 if ( n < 0 ) 
01402                                 {
01403                                         Com_Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
01404                                         continue;
01405                                 }
01406                                 ri->torsoYawRangeRight = n;
01407                                 continue;
01408                         }
01409 
01410                         //torsoPitchRangeUp
01411                         if ( !Q_stricmp( token, "torsoPitchRangeUp" ) ) 
01412                         {
01413                                 if ( COM_ParseInt( &p, &n ) ) 
01414                                 {
01415                                         SkipRestOfLine( &p );
01416                                         continue;
01417                                 }
01418                                 if ( n < 0 ) 
01419                                 {
01420                                         Com_Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
01421                                         continue;
01422                                 }
01423                                 ri->torsoPitchRangeUp = n;
01424                                 continue;
01425                         }
01426 
01427                         //torsoPitchRangeDown
01428                         if ( !Q_stricmp( token, "torsoPitchRangeDown" ) ) 
01429                         {
01430                                 if ( COM_ParseInt( &p, &n ) ) 
01431                                 {
01432                                         SkipRestOfLine( &p );
01433                                         continue;
01434                                 }
01435                                 if ( n < 0 ) 
01436                                 {
01437                                         Com_Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
01438                                         continue;
01439                                 }
01440                                 ri->torsoPitchRangeDown = n;
01441                                 continue;
01442                         }
01443 
01444                         // Uniform XYZ scale
01445                         if ( !Q_stricmp( token, "scale" ) ) 
01446                         {
01447                                 if ( COM_ParseInt( &p, &n ) ) 
01448                                 {
01449                                         SkipRestOfLine( &p );
01450                                         continue;
01451                                 }
01452                                 if ( n < 0 ) 
01453                                 {
01454                                         Com_Printf(  "bad %s in NPC '%s'\n", token, NPCName );
01455                                         continue;
01456                                 }
01457                                 if (n != 100)
01458                                 {
01459                                         NPC->client->ps.iModelScale = n; //so the client knows
01460                                         if (n >= 1024)
01461                                         {
01462                                                 Com_Printf("WARNING: MP does not support scaling up to or over 1024%\n");
01463                                                 n = 1023;
01464                                         }
01465 
01466                                         NPC->modelScale[0] = NPC->modelScale[1] = NPC->modelScale[2] = n/100.0f;
01467                                 }
01468                                 continue;
01469                         }
01470 
01471                         //X scale
01472                         if ( !Q_stricmp( token, "scaleX" ) ) 
01473                         {
01474                                 if ( COM_ParseInt( &p, &n ) ) 
01475                                 {
01476                                         SkipRestOfLine( &p );
01477                                         continue;
01478                                 }
01479                                 if ( n < 0 ) 
01480                                 {
01481                                         Com_Printf(  "bad %s in NPC '%s'\n", token, NPCName );
01482                                         continue;
01483                                 }
01484                                 if (n != 100)
01485                                 {
01486                                         Com_Printf("MP doesn't support xyz scaling, use 'scale'.\n");
01487                                         //NPC->s.modelScale[0] = n/100.0f;
01488                                 }
01489                                 continue;
01490                         }
01491 
01492                         //Y scale
01493                         if ( !Q_stricmp( token, "scaleY" ) ) 
01494                         {
01495                                 if ( COM_ParseInt( &p, &n ) ) 
01496                                 {
01497                                         SkipRestOfLine( &p );
01498                                         continue;
01499                                 }
01500                                 if ( n < 0 ) 
01501                                 {
01502                                         Com_Printf(  "bad %s in NPC '%s'\n", token, NPCName );
01503                                         continue;
01504                                 }
01505                                 if (n != 100)
01506                                 {
01507                                         Com_Printf("MP doesn't support xyz scaling, use 'scale'.\n");
01508                                         //NPC->s.modelScale[1] = n/100.0f;
01509                                 }
01510                                 continue;
01511                         }
01512 
01513                         //Z scale
01514                         if ( !Q_stricmp( token, "scaleZ" ) ) 
01515                         {
01516                                 if ( COM_ParseInt( &p, &n ) ) 
01517                                 {
01518                                         SkipRestOfLine( &p );
01519                                         continue;
01520                                 }
01521                                 if ( n < 0 ) 
01522                                 {
01523                                         Com_Printf(  "bad %s in NPC '%s'\n", token, NPCName );
01524                                         continue;
01525                                 }
01526                                 if (n != 100)
01527                                 {
01528                                         Com_Printf("MP doesn't support xyz scaling, use 'scale'.\n");
01529                                 //      NPC->s.modelScale[2] = n/100.0f;
01530                                 }
01531                                 continue;
01532                         }
01533 
01534         //===AI STATS=====================================================================
01535                         if ( !parsingPlayer )
01536                         {
01537                                 // aggression
01538                                 if ( !Q_stricmp( token, "aggression" ) ) {
01539                                         if ( COM_ParseInt( &p, &n ) ) {
01540                                                 SkipRestOfLine( &p );
01541                                                 continue;
01542                                         }
01543                                         if ( n < 1 || n > 5 ) {
01544                                                 Com_Printf(  "bad %s in NPC '%s'\n", token, NPCName );
01545                                                 continue;
01546                                         }
01547                                         if ( NPC->NPC )
01548                                         {
01549                                                 stats->aggression = n;
01550                                         }
01551                                         continue;
01552                                 }
01553 
01554                                 // aim
01555                                 if ( !Q_stricmp( token, "aim" ) ) {
01556                                         if ( COM_ParseInt( &p, &n ) ) {
01557                                                 SkipRestOfLine( &p );
01558                                                 continue;
01559                                         }
01560                                         if ( n < 1 || n > 5 ) {
01561                                                 Com_Printf( "bad %s in NPC '%s'\n", token, NPCName );
01562                                                 continue;
01563                                         }
01564                                         if ( NPC->NPC )
01565                                         {
01566                                                 stats->aim = n;
01567                                         }
01568                                         continue;
01569                                 }
01570 
01571                                 // earshot
01572                                 if ( !Q_stricmp( token, "earshot" ) ) {
01573                                         if ( COM_ParseFloat( &p, &f ) ) {
01574                                                 SkipRestOfLine( &p );
01575                                                 continue;
01576                                         }
01577                                         if ( f < 0.0f ) 
01578                                         {
01579                                                 Com_Printf( "bad %s in NPC '%s'\n", token, NPCName );
01580                                                 continue;
01581                                         }
01582                                         if ( NPC->NPC )
01583                                         {
01584                                                 stats->earshot = f;
01585                                         }
01586                                         continue;
01587                                 }
01588 
01589                                 // evasion
01590                                 if ( !Q_stricmp( token, "evasion" ) ) 
01591                                 {
01592                                         if ( COM_ParseInt( &p, &n ) ) 
01593                                         {
01594                                                 SkipRestOfLine( &p );
01595                                                 continue;
01596                                         }
01597                                         if ( n < 1 || n > 5 ) 
01598                                         {
01599                                                 Com_Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
01600                                                 continue;
01601                                         }
01602                                         if ( NPC->NPC )
01603                                         {
01604                                                 stats->evasion = n;
01605                                         }
01606                                         continue;
01607                                 }
01608 
01609                                 // hfov
01610                                 if ( !Q_stricmp( token, "hfov" ) ) {
01611                                         if ( COM_ParseInt( &p, &n ) ) {
01612                                                 SkipRestOfLine( &p );
01613                                                 continue;
01614                                         }
01615                                         if ( n < 30 || n > 180 ) {
01616                                                 Com_Printf(  "bad %s in NPC '%s'\n", token, NPCName );
01617                                                 continue;
01618                                         }
01619                                         if ( NPC->NPC )
01620                                         {
01621                                                 stats->hfov = n;// / 2; //FIXME: Why was this being done?!
01622                                         }
01623                                         continue;
01624                                 }
01625 
01626                                 // intelligence
01627                                 if ( !Q_stricmp( token, "intelligence" ) ) {
01628                                         if ( COM_ParseInt( &p, &n ) ) {
01629                                                 SkipRestOfLine( &p );
01630                                                 continue;
01631                                         }
01632                                         if ( n < 1 || n > 5 ) {
01633                                                 Com_Printf(  "bad %s in NPC '%s'\n", token, NPCName );
01634                                                 continue;
01635                                         }
01636                                         if ( NPC->NPC )
01637                                         {
01638                                                 stats->intelligence = n;
01639                                         }
01640                                         continue;
01641                                 }
01642                                 
01643                                 // move
01644                                 if ( !Q_stricmp( token, "move" ) ) {
01645                                         if ( COM_ParseInt( &p, &n ) ) {
01646                                                 SkipRestOfLine( &p );
01647                                                 continue;
01648                                         }
01649                                         if ( n < 1 || n > 5 ) {
01650                                                 Com_Printf(  "bad %s in NPC '%s'\n", token, NPCName );
01651                                                 continue;
01652                                         }
01653                                         if ( NPC->NPC )
01654                                         {
01655                                                 stats->move = n;
01656                                         }
01657                                         continue;
01658                                 }
01659 
01660                                 // reactions
01661                                 if ( !Q_stricmp( token, "reactions" ) ) {
01662                                         if ( COM_ParseInt( &p, &n ) ) {
01663                                                 SkipRestOfLine( &p );
01664                                                 continue;
01665                                         }
01666                                         if ( n < 1 || n > 5 ) {
01667                                                 Com_Printf( "bad %s in NPC '%s'\n", token, NPCName );
01668                                                 continue;
01669                                         }
01670                                         if ( NPC->NPC )
01671                                         {
01672                                                 stats->reactions = n;
01673                                         }
01674                                         continue;
01675                                 }
01676 
01677                                 // shootDistance
01678                                 if ( !Q_stricmp( token, "shootDistance" ) ) {
01679                                         if ( COM_ParseFloat( &p, &f ) ) {
01680                                                 SkipRestOfLine( &p );
01681                                                 continue;
01682                                         }
01683                                         if ( f < 0.0f ) 
01684                                         {
01685                                                 Com_Printf( "bad %s in NPC '%s'\n", token, NPCName );
01686                                                 continue;
01687                                         }
01688                                         if ( NPC->NPC )
01689                                         {
01690                                                 stats->shootDistance = f;
01691                                         }
01692                                         continue;
01693                                 }
01694 
01695                                 // vfov
01696                                 if ( !Q_stricmp( token, "vfov" ) ) {
01697                                         if ( COM_ParseInt( &p, &n ) ) {
01698                                                 SkipRestOfLine( &p );
01699                                                 continue;
01700                                         }
01701                                         if ( n < 30 || n > 180 ) {
01702                                                 Com_Printf(  "bad %s in NPC '%s'\n", token, NPCName );
01703                                                 continue;
01704                                         }
01705                                         if ( NPC->NPC )
01706                                         {
01707                                                 stats->vfov = n / 2;
01708                                         }
01709                                         continue;
01710                                 }
01711 
01712                                 // vigilance
01713                                 if ( !Q_stricmp( token, "vigilance" ) ) {
01714                                         if ( COM_ParseFloat( &p, &f ) ) {
01715                                                 SkipRestOfLine( &p );
01716                                                 continue;
01717                                         }
01718                                         if ( f < 0.0f ) 
01719                                         {
01720                                                 Com_Printf( "bad %s in NPC '%s'\n", token, NPCName );
01721                                                 continue;
01722                                         }
01723                                         if ( NPC->NPC )
01724                                         {
01725                                                 stats->vigilance = f;
01726                                         }
01727                                         continue;
01728                                 }
01729 
01730                                 // visrange
01731                                 if ( !Q_stricmp( token, "visrange" ) ) {
01732                                         if ( COM_ParseFloat( &p, &f ) ) {
01733                                                 SkipRestOfLine( &p );
01734                                                 continue;
01735                                         }
01736                                         if ( f < 0.0f ) 
01737                                         {
01738                                                 Com_Printf( "bad %s in NPC '%s'\n", token, NPCName );
01739                                                 continue;
01740                                         }
01741                                         if ( NPC->NPC )
01742                                         {
01743                                                 stats->visrange = f;
01744                                         }
01745                                         continue;
01746                                 }
01747 
01748                                 // race
01749                 //              if ( !Q_stricmp( token, "race" ) ) 
01750                 //              {
01751                 //                      if ( COM_ParseString( &p, &value ) ) 
01752                 //                      {
01753                 //                              continue;
01754                 //                      }
01755                 //                      NPC->client->race = TranslateRaceName(value);
01756                 //                      continue;
01757                 //              }
01758 
01759                                 // rank
01760                                 if ( !Q_stricmp( token, "rank" ) ) 
01761                                 {
01762                                         if ( COM_ParseString( &p, &value ) ) 
01763                                         {
01764                                                 continue;
01765                                         }
01766                                         if ( NPC->NPC )
01767                                         {
01768                                                 NPC->NPC->rank = TranslateRankName(value);
01769                                         }
01770                                         continue;
01771                                 }
01772                         }
01773 
01774                         // health
01775                         if ( !Q_stricmp( token, "health" ) ) 
01776                         {
01777                                 if ( COM_ParseInt( &p, &n ) ) 
01778                                 {
01779                                         SkipRestOfLine( &p );
01780                                         continue;
01781                                 }
01782                                 if ( n < 0 ) 
01783                                 {
01784                                         Com_Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
01785                                         continue;
01786                                 }
01787                                 if ( NPC->NPC )
01788                                 {
01789                                         stats->health = n;
01790                                 }
01791                                 else if ( parsingPlayer )
01792                                 {
01793                                         NPC->client->ps.stats[STAT_MAX_HEALTH] = NPC->client->pers.maxHealth = n;
01794                                 }
01795                                 continue;
01796                         }
01797 
01798                         // fullName
01799                         if ( !Q_stricmp( token, "fullName" ) ) 
01800                         {
01801                                 if ( COM_ParseString( &p, &value ) ) 
01802                                 {
01803                                         continue;
01804                                 }
01805                                 NPC->fullName = G_NewString(value);
01806                                 continue;
01807                         }
01808 
01809                         // playerTeam
01810                         if ( !Q_stricmp( token, "playerTeam" ) ) 
01811                         {
01812                                 char tk[4096]; //rww - hackilicious!
01813 
01814                                 if ( COM_ParseString( &p, &value ) ) 
01815                                 {
01816                                         continue;
01817                                 }
01818                                 Com_sprintf(tk, sizeof(tk), "NPC%s", token);
01819                                 NPC->client->playerTeam = NPC->s.teamowner = (team_t)GetIDForString( TeamTable, tk );//TranslateTeamName(value);
01820                                 continue;
01821                         }
01822 
01823                         // enemyTeam
01824                         if ( !Q_stricmp( token, "enemyTeam" ) ) 
01825                         {
01826                                 char tk[4096]; //rww - hackilicious!
01827 
01828                                 if ( COM_ParseString( &p, &value ) ) 
01829                                 {
01830                                         continue;
01831                                 }
01832                                 Com_sprintf(tk, sizeof(tk), "NPC%s", token);
01833                                 NPC->client->enemyTeam = (team_t)GetIDForString( TeamTable, tk );//TranslateTeamName(value);
01834                                 continue;
01835                         }
01836 
01837                         // class
01838                         if ( !Q_stricmp( token, "class" ) ) 
01839                         {
01840                                 if ( COM_ParseString( &p, &value ) ) 
01841                                 {
01842                                         continue;
01843                                 }
01844                                 NPC->client->NPC_class = (class_t)GetIDForString( ClassTable, value );
01845                                 NPC->s.NPC_class = NPC->client->NPC_class; //we actually only need this value now, but at the moment I don't feel like changing the 200+ references to client->NPC_class.
01846 
01847                                 // No md3's for vehicles.
01848                                 if ( NPC->client->NPC_class == CLASS_VEHICLE )
01849                                 {
01850                                         if ( !NPC->m_pVehicle )
01851                                         {//you didn't spawn this guy right!
01852                                                 Com_Printf ( S_COLOR_RED "ERROR: Tried to spawn a vehicle NPC (%s) without using NPC_Vehicle or 'NPC spawn vehicle <vehiclename>'!!!  Bad, bad, bad!  Shame on you!\n", NPCName );
01853                                                 return qfalse;
01854                                         }
01855                                         md3Model = qfalse;
01856                                 }
01857 
01858                                 continue;
01859                         }
01860 
01861                         // dismemberment probability for head
01862                         if ( !Q_stricmp( token, "dismemberProbHead" ) ) {
01863                                 if ( COM_ParseInt( &p, &n ) ) {
01864                                         SkipRestOfLine( &p );
01865                                         continue;
01866                                 }
01867                                 if ( n < 0 ) 
01868                                 {
01869                                         Com_Printf( "bad %s in NPC '%s'\n", token, NPCName );
01870                                         continue;
01871                                 }
01872                                 if ( NPC->NPC )
01873                                 {
01874                                 //      NPC->client->dismemberProbHead = n;
01875                                         //rwwFIXMEFIXME: support for this?
01876                                 }
01877                                 continue;
01878                         }
01879 
01880                         // dismemberment probability for arms
01881                         if ( !Q_stricmp( token, "dismemberProbArms" ) ) {
01882                                 if ( COM_ParseInt( &p, &n ) ) {
01883                                         SkipRestOfLine( &p );
01884                                         continue;
01885                                 }
01886                                 if ( n < 0 ) 
01887                                 {
01888                                         Com_Printf( "bad %s in NPC '%s'\n", token, NPCName );
01889                                         continue;
01890                                 }
01891                                 if ( NPC->NPC )
01892                                 {
01893                                 //      NPC->client->dismemberProbArms = n;
01894                                 }
01895                                 continue;
01896                         }
01897 
01898                         // dismemberment probability for hands
01899                         if ( !Q_stricmp( token, "dismemberProbHands" ) ) {
01900                                 if ( COM_ParseInt( &p, &n ) ) {
01901                                         SkipRestOfLine( &p );
01902                                         continue;
01903                                 }
01904                                 if ( n < 0 ) 
01905                                 {
01906                                         Com_Printf( "bad %s in NPC '%s'\n", token, NPCName );
01907                                         continue;
01908                                 }
01909                                 if ( NPC->NPC )
01910                                 {
01911                                 //      NPC->client->dismemberProbHands = n;
01912                                 }
01913                                 continue;
01914                         }
01915 
01916                         // dismemberment probability for waist
01917                         if ( !Q_stricmp( token, "dismemberProbWaist" ) ) {
01918                                 if ( COM_ParseInt( &p, &n ) ) {
01919                                         SkipRestOfLine( &p );
01920                                         continue;
01921                                 }
01922                                 if ( n < 0 ) 
01923                                 {
01924                                         Com_Printf( "bad %s in NPC '%s'\n", token, NPCName );
01925                                         continue;
01926                                 }
01927                                 if ( NPC->NPC )
01928                                 {
01929                                 //      NPC->client->dismemberProbWaist = n;
01930                                 }
01931                                 continue;
01932                         }
01933 
01934                         // dismemberment probability for legs
01935                         if ( !Q_stricmp( token, "dismemberProbLegs" ) ) {
01936                                 if ( COM_ParseInt( &p, &n ) ) {
01937                                         SkipRestOfLine( &p );
01938                                         continue;
01939                                 }
01940                                 if ( n < 0 ) 
01941                                 {
01942                                         Com_Printf( "bad %s in NPC '%s'\n", token, NPCName );
01943                                         continue;
01944                                 }
01945                                 if ( NPC->NPC )
01946                                 {
01947                                 //      NPC->client->dismemberProbLegs = n;
01948                                 }
01949                                 continue;
01950                         }
01951 
01952         //===MOVEMENT STATS============================================================
01953                         
01954                         if ( !Q_stricmp( token, "width" ) ) 
01955                         {
01956                                 if ( COM_ParseInt( &p, &n ) ) 
01957                                 {
01958                                         continue;
01959                                 }
01960 
01961                                 NPC->r.mins[0] = NPC->r.mins[1] = -n;
01962                                 NPC->r.maxs[0] = NPC->r.maxs[1] = n;
01963                                 continue;
01964                         }
01965 
01966                         if ( !Q_stricmp( token, "height" ) ) 
01967                         {
01968                                 if ( COM_ParseInt( &p, &n ) ) 
01969                                 {
01970                                         continue;
01971                                 }
01972                                 if ( NPC->client->NPC_class == CLASS_VEHICLE
01973                                         && NPC->m_pVehicle
01974                                         && NPC->m_pVehicle->m_pVehicleInfo
01975                                         && NPC->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER )
01976                                 {//a flying vehicle's origin must be centered in bbox and it should spawn on the ground
01977                                         //trace_t               tr;
01978                                         //vec3_t                bottom;
01979                                         //float         adjust = 32.0f;
01980                                         NPC->r.maxs[2] = NPC->client->ps.standheight = (n/2.0f);
01981                                         NPC->r.mins[2] = -NPC->r.maxs[2];
01982                                         NPC->s.origin[2] += (DEFAULT_MINS_2-NPC->r.mins[2])+0.125f;
01983                                         VectorCopy(NPC->s.origin, NPC->client->ps.origin);
01984                                         VectorCopy(NPC->s.origin, NPC->r.currentOrigin);
01985                                         G_SetOrigin( NPC, NPC->s.origin );
01986                                         trap_LinkEntity(NPC);
01987                                         //now trace down
01988                                         /*
01989                                         VectorCopy( NPC->s.origin, bottom );
01990                                         bottom[2] -= adjust;
01991                                         trap_Trace( &tr, NPC->s.origin, NPC->r.mins, NPC->r.maxs, bottom, NPC->s.number, MASK_NPCSOLID );
01992                                         if ( !tr.allsolid && !tr.startsolid )
01993                                         {
01994                                                 G_SetOrigin( NPC, tr.endpos );
01995                                                 trap_LinkEntity(NPC);
01996                                         }
01997                                         */
01998                                 }
01999                                 else
02000                                 {
02001                                         NPC->r.mins[2] = DEFAULT_MINS_2;//Cannot change
02002                                         NPC->r.maxs[2] = NPC->client->ps.standheight = n + DEFAULT_MINS_2;
02003                                 }
02004                                 NPC->radius = n;
02005                                 continue;
02006                         }
02007 
02008                         if ( !Q_stricmp( token, "crouchheight" ) ) 
02009                         {
02010                                 if ( COM_ParseInt( &p, &n ) ) 
02011                                 {
02012                                         continue;
02013                                 }
02014 
02015                                 NPC->client->ps.crouchheight = n + DEFAULT_MINS_2;
02016                                 continue;
02017                         }
02018 
02019                         if ( !parsingPlayer )
02020                         {
02021                                 if ( !Q_stricmp( token, "movetype" ) ) 
02022                                 {
02023                                         if ( COM_ParseString( &p, &value ) ) 
02024                                         {
02025                                                 continue;
02026                                         }
02027                                         if ( Q_stricmp( "flyswim", value ) == 0 )
02028                                         {
02029                                                 NPC->client->ps.eFlags2 |= EF2_FLYING;
02030                                         }
02031                                         //NPC->client->moveType = (movetype_t)MoveTypeNameToEnum(value);
02032                                         //rwwFIXMEFIXME: support for movetypes
02033                                         continue;
02034                                 }
02035                                         
02036                                 // yawSpeed
02037                                 if ( !Q_stricmp( token, "yawSpeed" ) ) {
02038                                         if ( COM_ParseInt( &p, &n ) ) {
02039                                                 SkipRestOfLine( &p );
02040                                                 continue;
02041                                         }
02042                                         if ( n <= 0) {
02043                                                 Com_Printf(  "bad %s in NPC '%s'\n", token, NPCName );
02044                                                 continue;
02045                                         }
02046                                         if ( NPC->NPC )
02047                                         {
02048                                                 stats->yawSpeed = ((float)(n));
02049                                         }
02050                                         continue;
02051                                 }
02052 
02053                                 // walkSpeed
02054                                 if ( !Q_stricmp( token, "walkSpeed" ) ) 
02055                                 {
02056                                         if ( COM_ParseInt( &p, &n ) ) 
02057                                         {
02058                                                 SkipRestOfLine( &p );
02059                                                 continue;
02060                                         }
02061                                         if ( n < 0 ) 
02062                                         {
02063                                                 Com_Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
02064                                                 continue;
02065                                         }
02066                                         if ( NPC->NPC )
02067                                         {
02068                                                 stats->walkSpeed = n;
02069                                         }
02070                                         continue;
02071                                 }
02072                                 
02073                                 //runSpeed
02074                                 if ( !Q_stricmp( token, "runSpeed" ) ) 
02075                                 {
02076                                         if ( COM_ParseInt( &p, &n ) ) 
02077                                         {
02078                                                 SkipRestOfLine( &p );
02079                                                 continue;
02080                                         }
02081                                         if ( n < 0 ) 
02082                                         {
02083                                                 Com_Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
02084                                                 continue;
02085                                         }
02086                                         if ( NPC->NPC )
02087                                         {
02088                                                 stats->runSpeed = n;
02089                                         }
02090                                         continue;
02091                                 }
02092 
02093                                 //acceleration
02094                                 if ( !Q_stricmp( token, "acceleration" ) ) 
02095                                 {
02096                                         if ( COM_ParseInt( &p, &n ) ) 
02097                                         {
02098                                                 SkipRestOfLine( &p );
02099                                                 continue;
02100                                         }
02101                                         if ( n < 0 ) 
02102                                         {
02103                                                 Com_Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
02104                                                 continue;
02105                                         }
02106                                         if ( NPC->NPC )
02107                                         {
02108                                                 stats->acceleration = n;
02109                                         }
02110                                         continue;
02111                                 }
02112                                 //sex - skip in MP
02113                                 if ( !Q_stricmp( token, "sex" ) ) 
02114                                 {
02115                                         SkipRestOfLine( &p );
02116                                         continue;
02117                                 }
02118 //===MISC===============================================================================
02119                                 // default behavior
02120                                 if ( !Q_stricmp( token, "behavior" ) ) 
02121                                 {
02122                                         if ( COM_ParseInt( &p, &n ) ) 
02123                                         {
02124                                                 SkipRestOfLine( &p );
02125                                                 continue;
02126                                         }
02127                                         if ( n < BS_DEFAULT || n >= NUM_BSTATES ) 
02128                                         {
02129                                                 Com_Printf( S_COLOR_YELLOW"WARNING: bad %s in NPC '%s'\n", token, NPCName );
02130                                                 continue;
02131                                         }
02132                                         if ( NPC->NPC )
02133                                         {
02134                                                 NPC->NPC->defaultBehavior = (bState_t)(n);
02135                                         }
02136                                         continue;
02137                                 }
02138                         }
02139 
02140                         // snd
02141                         if ( !Q_stricmp( token, "snd" ) ) 
02142                         {
02143                                 if ( COM_ParseString( &p, &value ) ) 
02144                                 {
02145                                         continue;
02146                                 }
02147                                 if ( !(NPC->r.svFlags&SVF_NO_BASIC_SOUNDS) )
02148                                 {
02149                                         //FIXME: store this in some sound field or parse in the soundTable like the animTable...
02150                                         Q_strncpyz( sound, value, sizeof( sound ) );
02151                                         patch = strstr( sound, "/" );
02152                                         if ( patch ) 
02153                                         {
02154                                                 *patch = 0;
02155                                         }
02156                                 //      ci->customBasicSoundDir = G_NewString( sound );
02157                                         //rwwFIXMEFIXME: Hooray for violating client server rules
02158                                 }
02159                                 continue;
02160                         }
02161 
02162                         // sndcombat
02163                         if ( !Q_stricmp( token, "sndcombat" ) ) 
02164                         {
02165                                 if ( COM_ParseString( &p, &value ) ) 
02166                                 {
02167                                         continue;
02168                                 }
02169                                 if ( !(NPC->r.svFlags&SVF_NO_COMBAT_SOUNDS) )
02170                                 {
02171                                         //FIXME: store this in some sound field or parse in the soundTable like the animTable...
02172                                         Q_strncpyz( sound, value, sizeof( sound ) );
02173                                         patch = strstr( sound, "/" );
02174                                         if ( patch ) 
02175                                         {
02176                                                 *patch = 0;
02177                                         }
02178                                 //      ci->customCombatSoundDir = G_NewString( sound );
02179                                 }
02180                                 continue;
02181                         }
02182                         
02183                         // sndextra
02184                         if ( !Q_stricmp( token, "sndextra" ) ) 
02185                         {
02186                                 if ( COM_ParseString( &p, &value ) ) 
02187                                 {
02188                                         continue;
02189                                 }
02190                                 if ( !(NPC->r.svFlags&SVF_NO_EXTRA_SOUNDS) )
02191                                 {
02192                                         //FIXME: store this in some sound field or parse in the soundTable like the animTable...
02193                                         Q_strncpyz( sound, value, sizeof( sound ) );
02194                                         patch = strstr( sound, "/" );
02195                                         if ( patch ) 
02196                                         {
02197                                                 *patch = 0;
02198                                         }
02199                                 //      ci->customExtraSoundDir = G_NewString( sound );
02200                                 }
02201                                 continue;
02202                         }
02203 
02204                         // sndjedi
02205                         if ( !Q_stricmp( token, "sndjedi" ) ) 
02206                         {
02207                                 if ( COM_ParseString( &p, &value ) ) 
02208                                 {
02209                                         continue;
02210                                 }
02211                                 if ( !(NPC->r.svFlags&SVF_NO_EXTRA_SOUNDS) )
02212                                 {
02213                                         //FIXME: store this in some sound field or parse in the soundTable like the animTable...
02214                                         Q_strncpyz( sound, value, sizeof( sound ) );
02215                                         patch = strstr( sound, "/" );
02216                                         if ( patch ) 
02217                                         {
02218                                                 *patch = 0;
02219                                         }
02220                                         //ci->customJediSoundDir = G_NewString( sound );
02221                                 }
02222                                 continue;
02223                         }
02224 
02225                         //New NPC/jedi stats:
02226                         //starting weapon
02227                         if ( !Q_stricmp( token, "weapon" ) ) 
02228                         {
02229                                 int weap;
02230 
02231                                 if ( COM_ParseString( &p, &value ) ) 
02232                                 {
02233                                         continue;
02234                                 }
02235                                 //FIXME: need to precache the weapon, too?  (in above func)
02236                                 weap = GetIDForString( WPTable, value );
02237                                 if ( weap >= WP_NONE && weap <= WP_NUM_WEAPONS )
02238                                 {
02239                                         NPC->client->ps.weapon = weap;
02240                                         NPC->client->ps.stats[STAT_WEAPONS] |= ( 1 << NPC->client->ps.weapon );
02241                                         if ( weap > WP_NONE )
02242                                         {
02243                                         //      RegisterItem( FindItemForWeapon( (weapon_t)(NPC->client->ps.weapon) ) );        //precache the weapon
02244                                                 NPC->client->ps.ammo[weaponData[NPC->client->ps.weapon].ammoIndex] = 100;//FIXME: max ammo!
02245                                         }
02246                                 }
02247                                 continue;
02248                         }
02249                         
02250                         if ( !parsingPlayer )
02251                         {
02252                                 //altFire
02253                                 if ( !Q_stricmp( token, "altFire" ) ) 
02254                                 {
02255                                         if ( COM_ParseInt( &p, &n ) ) 
02256                                         {
02257                                                 SkipRestOfLine( &p );
02258                                                 continue;
02259                                         }
02260                                         if ( NPC->NPC )
02261                                         {
02262                                                 if ( n != 0 )
02263                                                 {
02264                                                         NPC->NPC->scriptFlags |= SCF_ALT_FIRE;
02265                                                 }
02266                                         }
02267                                         continue;
02268                                 }
02269                                 //Other unique behaviors/numbers that are currently hardcoded?
02270                         }
02271 
02272                         //force powers
02273                         fp = GetIDForString( FPTable, token );
02274                         if ( fp >= FP_FIRST && fp < NUM_FORCE_POWERS )
02275                         {
02276                                 if ( COM_ParseInt( &p, &n ) ) 
02277                                 {
02278                                         SkipRestOfLine( &p );
02279                                         continue;
02280                                 }
02281                                 //FIXME: need to precache the fx, too?  (in above func)
02282                                 //cap
02283                                 if ( n > 5 )
02284                                 {
02285                                         n = 5;
02286                                 }
02287                                 else if ( n < 0 )
02288                                 {
02289                                         n = 0;
02290                                 }
02291                                 if ( n )
02292                                 {//set
02293                                         NPC->client->ps.fd.forcePowersKnown |= ( 1 << fp );
02294                                 }
02295                                 else
02296                                 {//clear
02297                                         NPC->client->ps.fd.forcePowersKnown &= ~( 1 << fp );
02298                                 }
02299                                 NPC->client->ps.fd.forcePowerLevel[fp] = n;
02300                                 continue;
02301                         }
02302 
02303                         //max force power
02304                         if ( !Q_stricmp( token, "forcePowerMax" ) ) 
02305                         {
02306                                 if ( COM_ParseInt( &p, &n ) ) 
02307                                 {
02308                                         SkipRestOfLine( &p );
02309                                         continue;
02310                                 }
02311                                 NPC->client->ps.fd.forcePowerMax = n;
02312                                 continue;
02313                         }
02314 
02315                         //force regen rate - default is 100ms
02316                         if ( !Q_stricmp( token, "forceRegenRate" ) ) 
02317                         {
02318                                 if ( COM_ParseInt( &p, &n ) ) 
02319                                 {
02320                                         SkipRestOfLine( &p );
02321                                         continue;
02322                                 }
02323                                 //NPC->client->ps.forcePowerRegenRate = n;
02324                                 //rwwFIXMEFIXME: support this?
02325                                 continue;
02326                         }
02327 
02328                         //force regen amount - default is 1 (points per second)
02329                         if ( !Q_stricmp( token, "forceRegenAmount" ) ) 
02330                         {
02331                                 if ( COM_ParseInt( &p, &n ) ) 
02332                                 {
02333                                         SkipRestOfLine( &p );
02334                                         continue;
02335                                 }
02336                                 //NPC->client->ps.forcePowerRegenAmount = n;
02337                                 //rwwFIXMEFIXME: support this?
02338                                 continue;
02339                         }
02340 
02341                         //have a sabers.cfg and just name your saber in your NPCs.cfg/ICARUS script
02342                         //saber name
02343                         if ( !Q_stricmp( token, "saber" ) ) 
02344                         {
02345                                 char *saberName;
02346 
02347                                 if ( COM_ParseString( &p, &value ) ) 
02348                                 {
02349                                         continue;
02350                                 }
02351 
02352                                 saberName = (char *)BG_TempAlloc(4096);//G_NewString( value );
02353                                 strcpy(saberName, value);
02354 
02355                                 WP_SaberParseParms( saberName, &NPC->client->saber[0] );
02356                                 npcSaber1 = G_ModelIndex(va("@%s", saberName));
02357 
02358                                 BG_TempFree(4096);
02359                                 continue;
02360                         }
02361                         
02362                         //second saber name
02363                         if ( !Q_stricmp( token, "saber2" ) ) 
02364                         {
02365                                 if ( COM_ParseString( &p, &value ) ) 
02366                                 {
02367                                         continue;
02368                                 }
02369 
02370                                 if ( !(NPC->client->saber[0].saberFlags&SFL_TWO_HANDED) )
02371                                 {//can't use a second saber if first one is a two-handed saber...?
02372                                         char *saberName = (char *)BG_TempAlloc(4096);//G_NewString( value );
02373                                         strcpy(saberName, value);
02374 
02375                                         WP_SaberParseParms( saberName, &NPC->client->saber[1] );
02376                                         if ( (NPC->client->saber[1].saberFlags&SFL_TWO_HANDED) )
02377                                         {//tsk tsk, can't use a twoHanded saber as second saber
02378                                                 WP_RemoveSaber( NPC->client->saber, 1 );
02379                                         }
02380                                         else
02381                                         {
02382                                                 //NPC->client->ps.dualSabers = qtrue;
02383                                                 npcSaber2 = G_ModelIndex(va("@%s", saberName));
02384                                         }
02385                                         BG_TempFree(4096);
02386                                 }
02387                                 continue;
02388                         }
02389 
02390                         // saberColor
02391                         if ( !Q_stricmp( token, "saberColor" ) ) 
02392                         {
02393                                 if ( COM_ParseString( &p, &value ) ) 
02394                                 {
02395                                         continue;
02396                                 }
02397                                 if ( NPC->client )
02398                                 {
02399                                         saber_colors_t color = TranslateSaberColor( value );
02400                                         for ( n = 0; n < MAX_BLADES; n++ )
02401                                         {
02402                                                 NPC->client->saber[0].blade[n].color = color;
02403                                         }
02404                                 }
02405                                 continue;
02406                         }
02407 
02408                         if ( !Q_stricmp( token, "saberColor2" ) ) 
02409                         {
02410                                 if ( COM_ParseString( &p, &value ) ) 
02411                                 {
02412                                         continue;
02413                                 }
02414                                 if ( NPC->client )
02415                                 {
02416                                         NPC->client->saber[0].blade[1].color = TranslateSaberColor( value );
02417                                 }
02418                                 continue;
02419                         }
02420 
02421                         if ( !Q_stricmp( token, "saberColor3" ) ) 
02422                         {
02423                                 if ( COM_ParseString( &p, &value ) ) 
02424                                 {
02425                                         continue;
02426                                 }
02427                                 if ( NPC->client )
02428                                 {
02429                                         NPC->client->saber[0].blade[2].color = TranslateSaberColor( value );
02430                                 }
02431                                 continue;
02432                         }
02433 
02434                         if ( !Q_stricmp( token, "saberColor4" ) ) 
02435                         {
02436                                 if ( COM_ParseString( &p, &value ) ) 
02437                                 {
02438                                         continue;
02439                                 }
02440                                 if ( NPC->client )
02441                                 {
02442                                         NPC->client->saber[0].blade[3].color = TranslateSaberColor( value );
02443                                 }
02444                                 continue;
02445                         }
02446 
02447                         if ( !Q_stricmp( token, "saberColor5" ) ) 
02448                         {
02449                                 if ( COM_ParseString( &p, &value ) ) 
02450                                 {
02451                                         continue;
02452                                 }
02453                                 if ( NPC->client )
02454                                 {
02455                                         NPC->client->saber[0].blade[4].color = TranslateSaberColor( value );
02456                                 }
02457                                 continue;
02458                         }
02459 
02460                         if ( !Q_stricmp( token, "saberColor6" ) ) 
02461                         {
02462                                 if ( COM_ParseString( &p, &value ) ) 
02463                                 {
02464                                         continue;
02465                                 }
02466                                 if ( NPC->client )
02467                                 {
02468                                         NPC->client->saber[0].blade[5].color = TranslateSaberColor( value );
02469                                 }
02470                                 continue;
02471                         }
02472 
02473                         if ( !Q_stricmp( token, "saberColor7" ) ) 
02474                         {
02475                                 if ( COM_ParseString( &p, &value ) ) 
02476                                 {
02477                                         continue;
02478                                 }
02479                                 if ( NPC->client )
02480                                 {
02481                                         NPC->client->saber[0].blade[6].color = TranslateSaberColor( value );
02482                                 }
02483                                 continue;
02484                         }
02485 
02486                         if ( !Q_stricmp( token, "saberColor8" ) ) 
02487                         {
02488                                 if ( COM_ParseString( &p, &value ) ) 
02489                                 {
02490                                         continue;
02491                                 }
02492                                 if ( NPC->client )
02493                                 {
02494                                         NPC->client->saber[0].blade[7].color = TranslateSaberColor( value );
02495                                 }
02496                                 continue;
02497                         }
02498 
02499                         if ( !Q_stricmp( token, "saber2Color" ) ) 
02500                         {
02501                                 if ( COM_ParseString( &p, &value ) ) 
02502                                 {
02503                                         continue;
02504                                 }
02505                                 if ( NPC->client )
02506                                 {
02507                                         saber_colors_t color = TranslateSaberColor( value );
02508                                         for ( n = 0; n < MAX_BLADES; n++ )
02509                                         {
02510                                                 NPC->client->saber[1].blade[n].color = color;
02511                                         }
02512                                 }
02513                                 continue;
02514                         }
02515 
02516                         if ( !Q_stricmp( token, "saber2Color2" ) ) 
02517                         {
02518                                 if ( COM_ParseString( &p, &value ) ) 
02519                                 {
02520                                         continue;
02521                                 }
02522                                 if ( NPC->client )
02523                                 {
02524                                         NPC->client->saber[1].blade[1].color = TranslateSaberColor( value );
02525                                 }
02526                                 continue;
02527                         }
02528 
02529                         if ( !Q_stricmp( token, "saber2Color3" ) ) 
02530                         {
02531                                 if ( COM_ParseString( &p, &value ) ) 
02532                                 {
02533                                         continue;
02534                                 }
02535                                 if ( NPC->client )
02536                                 {
02537                                         NPC->client->saber[1].blade[2].color = TranslateSaberColor( value );
02538                                 }
02539                                 continue;
02540                         }
02541 
02542                         if ( !Q_stricmp( token, "saber2Color4" ) ) 
02543                         {
02544                                 if ( COM_ParseString( &p, &value ) ) 
02545                                 {
02546                                         continue;
02547                                 }
02548                                 if ( NPC->client )
02549                                 {
02550                                         NPC->client->saber[1].blade[3].color = TranslateSaberColor( value );
02551                                 }
02552                                 continue;
02553                         }
02554 
02555                         if ( !Q_stricmp( token, "saber2Color5" ) ) 
02556                         {
02557                                 if ( COM_ParseString( &p, &value ) ) 
02558                                 {
02559                                         continue;
02560                                 }
02561                                 if ( NPC->client )
02562                                 {
02563                                         NPC->client->saber[1].blade[4].color = TranslateSaberColor( value );
02564                                 }
02565                                 continue;
02566                         }
02567 
02568                         if ( !Q_stricmp( token, "saber2Color6" ) ) 
02569                         {
02570                                 if ( COM_ParseString( &p, &value ) ) 
02571                                 {
02572                                         continue;
02573                                 }
02574                                 if ( NPC->client )
02575                                 {
02576                                         NPC->client->saber[1].blade[5].color = TranslateSaberColor( value );
02577                                 }
02578                                 continue;
02579                         }
02580 
02581                         if ( !Q_stricmp( token, "saber2Color7" ) ) 
02582                         {
02583                                 if ( COM_ParseString( &p, &value ) ) 
02584                                 {
02585                                         continue;
02586                                 }
02587                                 if ( NPC->client )
02588                                 {
02589                                         NPC->client->saber[1].blade[6].color = TranslateSaberColor( value );
02590                                 }
02591                                 continue;
02592                         }
02593 
02594                         if ( !Q_stricmp( token, "saber2Color8" ) ) 
02595                         {
02596                                 if ( COM_ParseString( &p, &value ) ) 
02597                                 {
02598                                         continue;
02599                                 }
02600                                 if ( NPC->client )
02601                                 {
02602                                         NPC->client->saber[1].blade[7].color = TranslateSaberColor( value );
02603                                 }
02604                                 continue;
02605                         }
02606 
02607                         //saber length
02608                         if ( !Q_stricmp( token, "saberLength" ) ) 
02609                         {
02610                                 if ( COM_ParseFloat( &p, &f ) ) 
02611                                 {
02612                                         SkipRestOfLine( &p );
02613                                         continue;
02614                                 }
02615                                 //cap
02616                                 if ( f < 4.0f )
02617                                 {
02618                                         f = 4.0f;
02619                                 }
02620 
02621                                 for ( n = 0; n < MAX_BLADES; n++ )
02622                                 {
02623                                         NPC->client->saber[0].blade[n].lengthMax = f;
02624                                 }
02625                                 continue;
02626                         }
02627 
02628                         if ( !Q_stricmp( token, "saberLength2" ) ) 
02629                         {
02630                                 if ( COM_ParseFloat( &p, &f ) ) 
02631                                 {
02632                                         SkipRestOfLine( &p );
02633                                         continue;
02634                                 }
02635                                 //cap
02636                                 if ( f < 4.0f )
02637                                 {
02638                                         f = 4.0f;
02639                                 }
02640                                 NPC->client->saber[0].blade[1].lengthMax = f;
02641                                 continue;
02642                         }
02643 
02644                         if ( !Q_stricmp( token, "saberLength3" ) ) 
02645                         {
02646                                 if ( COM_ParseFloat( &p, &f ) ) 
02647                                 {
02648                                         SkipRestOfLine( &p );
02649                                         continue;
02650                                 }
02651                                 //cap
02652                                 if ( f < 4.0f )
02653                                 {
02654                                         f = 4.0f;
02655                                 }
02656                                 NPC->client->saber[0].blade[2].lengthMax = f;
02657                                 continue;
02658                         }
02659 
02660                         if ( !Q_stricmp( token, "saberLength4" ) ) 
02661                         {
02662                                 if ( COM_ParseFloat( &p, &f ) ) 
02663                                 {
02664                                         SkipRestOfLine( &p );
02665                                         continue;
02666                                 }
02667                                 //cap
02668                                 if ( f < 4.0f )
02669                                 {
02670                                         f = 4.0f;
02671                                 }
02672                                 NPC->client->saber[0].blade[3].lengthMax = f;
02673                                 continue;
02674                         }
02675 
02676                         if ( !Q_stricmp( token, "saberLength5" ) ) 
02677                         {
02678                                 if ( COM_ParseFloat( &p, &f ) ) 
02679                                 {
02680                                         SkipRestOfLine( &p );
02681                                         continue;
02682                                 }
02683                                 //cap
02684                                 if ( f < 4.0f )
02685                                 {
02686                                         f = 4.0f;
02687                                 }
02688                                 NPC->client->saber[0].blade[4].lengthMax = f;
02689                                 continue;
02690                         }
02691 
02692                         if ( !Q_stricmp( token, "saberLength6" ) ) 
02693                         {
02694                                 if ( COM_ParseFloat( &p, &f ) ) 
02695                                 {
02696                                         SkipRestOfLine( &p );
02697                                         continue;
02698                                 }
02699                                 //cap
02700                                 if ( f < 4.0f )
02701                                 {
02702                                         f = 4.0f;
02703                                 }
02704                                 NPC->client->saber[0].blade[5].lengthMax = f;
02705                                 continue;
02706                         }
02707 
02708                         if ( !Q_stricmp( token, "saberLength7" ) ) 
02709                         {
02710                                 if ( COM_ParseFloat( &p, &f ) ) 
02711                                 {
02712                                         SkipRestOfLine( &p );
02713                                         continue;
02714                                 }
02715                                 //cap
02716                                 if ( f < 4.0f )
02717                                 {
02718                                         f = 4.0f;
02719                                 }
02720                                 NPC->client->saber[0].blade[6].lengthMax = f;
02721                                 continue;
02722                         }
02723 
02724                         if ( !Q_stricmp( token, "saberLength8" ) ) 
02725                         {
02726                                 if ( COM_ParseFloat( &p, &f ) ) 
02727                                 {
02728                                         SkipRestOfLine( &p );
02729                                         continue;
02730                                 }
02731                                 //cap
02732                                 if ( f < 4.0f )
02733                                 {
02734                                         f = 4.0f;
02735                                 }
02736                                 NPC->client->saber[0].blade[7].lengthMax = f;
02737                                 continue;
02738                         }
02739 
02740                         if ( !Q_stricmp( token, "saber2Length" ) ) 
02741                         {
02742                                 if ( COM_ParseFloat( &p, &f ) ) 
02743                                 {
02744                                         SkipRestOfLine( &p );
02745                                         continue;
02746                                 }
02747                                 //cap
02748                                 if ( f < 4.0f )
02749                                 {
02750                                         f = 4.0f;
02751                                 }
02752                                 for ( n = 0; n < MAX_BLADES; n++ )
02753                                 {
02754                                         NPC->client->saber[1].blade[n].lengthMax = f;
02755                                 }
02756                                 continue;
02757                         }
02758 
02759                         if ( !Q_stricmp( token, "saber2Length2" ) ) 
02760                         {
02761                                 if ( COM_ParseFloat( &p, &f ) ) 
02762                                 {
02763                                         SkipRestOfLine( &p );
02764                                         continue;
02765                                 }
02766                                 //cap
02767                                 if ( f < 4.0f )
02768                                 {
02769                                         f = 4.0f;
02770                                 }
02771                                 NPC->client->saber[1].blade[1].lengthMax = f;
02772                                 continue;
02773                         }
02774 
02775                         if ( !Q_stricmp( token, "saber2Length3" ) ) 
02776                         {
02777                                 if ( COM_ParseFloat( &p, &f ) ) 
02778                                 {
02779                                         SkipRestOfLine( &p );
02780                                         continue;
02781                                 }
02782                                 //cap
02783                                 if ( f < 4.0f )
02784                                 {
02785                                         f = 4.0f;
02786                                 }
02787                                 NPC->client->saber[1].blade[2].lengthMax = f;
02788                                 continue;
02789                         }
02790 
02791                         if ( !Q_stricmp( token, "saber2Length4" ) ) 
02792                         {
02793                                 if ( COM_ParseFloat( &p, &f ) ) 
02794                                 {
02795                                         SkipRestOfLine( &p );
02796                                         continue;
02797                                 }
02798                                 //cap
02799                                 if ( f < 4.0f )
02800                                 {
02801                                         f = 4.0f;
02802                                 }
02803                                 NPC->client->saber[1].blade[3].lengthMax = f;
02804                                 continue;
02805                         }
02806 
02807                         if ( !Q_stricmp( token, "saber2Length5" ) ) 
02808                         {
02809                                 if ( COM_ParseFloat( &p, &f ) ) 
02810                                 {
02811                                         SkipRestOfLine( &p );
02812                                         continue;
02813                                 }
02814                                 //cap
02815                                 if ( f < 4.0f )
02816                                 {
02817                                         f = 4.0f;
02818                                 }
02819                                 NPC->client->saber[1].blade[4].lengthMax = f;
02820                                 continue;
02821                         }
02822 
02823                         if ( !Q_stricmp( token, "saber2Length6" ) ) 
02824                         {
02825                                 if ( COM_ParseFloat( &p, &f ) ) 
02826                                 {
02827                                         SkipRestOfLine( &p );
02828                                         continue;
02829                                 }
02830                                 //cap
02831                                 if ( f < 4.0f )
02832                                 {
02833                                         f = 4.0f;
02834                                 }
02835                                 NPC->client->saber[1].blade[5].lengthMax = f;
02836                                 continue;
02837                         }
02838 
02839                         if ( !Q_stricmp( token, "saber2Length7" ) ) 
02840                         {
02841                                 if ( COM_ParseFloat( &p, &f ) ) 
02842                                 {
02843                                         SkipRestOfLine( &p );
02844                                         continue;
02845                                 }
02846                                 //cap
02847                                 if ( f < 4.0f )
02848                                 {
02849                                         f = 4.0f;
02850                                 }
02851                                 NPC->client->saber[1].blade[6].lengthMax = f;
02852                                 continue;
02853                         }
02854 
02855                         if ( !Q_stricmp( token, "saber2Length8" ) ) 
02856                         {
02857                                 if ( COM_ParseFloat( &p, &f ) ) 
02858                                 {
02859                                         SkipRestOfLine( &p );
02860                                         continue;
02861                                 }
02862                                 //cap
02863                                 if ( f < 4.0f )
02864                                 {
02865                                         f = 4.0f;
02866                                 }
02867                                 NPC->client->saber[1].blade[7].lengthMax = f;
02868                                 continue;
02869                         }
02870 
02871                         //saber radius
02872                         if ( !Q_stricmp( token, "saberRadius" ) ) 
02873                         {
02874                                 if ( COM_ParseFloat( &p, &f ) ) 
02875                                 {
02876                                         SkipRestOfLine( &p );
02877                                         continue;
02878                                 }
02879                                 //cap
02880                                 if ( f < 0.25f )
02881                                 {
02882                                         f = 0.25f;
02883                                 }
02884                                 for ( n = 0; n < MAX_BLADES; n++ )
02885                                 {
02886                                         NPC->client->saber[0].blade[n].radius = f;
02887                                 }
02888                                 continue;
02889                         }
02890 
02891                         if ( !Q_stricmp( token, "saberRadius2" ) ) 
02892                         {
02893                                 if ( COM_ParseFloat( &p, &f ) ) 
02894                                 {
02895                                         SkipRestOfLine( &p );
02896                                         continue;
02897                                 }
02898                                 //cap
02899                                 if ( f < 0.25f )
02900                                 {
02901                                         f = 0.25f;
02902                                 }
02903                                 NPC->client->saber[0].blade[1].radius = f;
02904                                 continue;
02905                         }
02906 
02907                         if ( !Q_stricmp( token, "saberRadius3" ) ) 
02908                         {
02909                                 if ( COM_ParseFloat( &p, &f ) ) 
02910                                 {
02911                                         SkipRestOfLine( &p );
02912                                         continue;
02913                                 }
02914                                 //cap
02915                                 if ( f < 0.25f )
02916                                 {
02917                                         f = 0.25f;
02918                                 }
02919                                 NPC->client->saber[0].blade[2].radius = f;
02920                                 continue;
02921                         }
02922 
02923                         if ( !Q_stricmp( token, "saberRadius4" ) ) 
02924                         {
02925                                 if ( COM_ParseFloat( &p, &f ) ) 
02926                                 {
02927                                         SkipRestOfLine( &p );
02928                                         continue;
02929                                 }
02930                                 //cap
02931                                 if ( f < 0.25f )
02932                                 {
02933                                         f = 0.25f;
02934                                 }
02935                                 NPC->client->saber[0].blade[3].radius = f;
02936                                 continue;
02937                         }
02938 
02939                         if ( !Q_stricmp( token, "saberRadius5" ) ) 
02940                         {
02941                                 if ( COM_ParseFloat( &p, &f ) ) 
02942                                 {
02943                                         SkipRestOfLine( &p );
02944                                         continue;
02945                                 }
02946                                 //cap
02947                                 if ( f < 0.25f )
02948                                 {
02949                                         f = 0.25f;
02950                                 }
02951                                 NPC->client->saber[0].blade[4].radius = f;
02952                                 continue;
02953                         }
02954 
02955                         if ( !Q_stricmp( token, "saberRadius6" ) ) 
02956                         {
02957                                 if ( COM_ParseFloat( &p, &f ) ) 
02958                                 {
02959                                         SkipRestOfLine( &p );
02960                                         continue;
02961                                 }
02962                                 //cap
02963                                 if ( f < 0.25f )
02964                                 {
02965                                         f = 0.25f;
02966                                 }
02967                                 NPC->client->saber[0].blade[5].radius = f;
02968                                 continue;
02969                         }
02970 
02971                         if ( !Q_stricmp( token, "saberRadius7" ) ) 
02972                         {
02973                                 if ( COM_ParseFloat( &p, &f ) ) 
02974                                 {
02975                                         SkipRestOfLine( &p );
02976                                         continue;
02977                                 }
02978                                 //cap
02979                                 if ( f < 0.25f )
02980                                 {
02981                                         f = 0.25f;
02982                                 }
02983                                 NPC->client->saber[0].blade[6].radius = f;
02984                                 continue;
02985                         }
02986 
02987                         if ( !Q_stricmp( token, "saberRadius8" ) ) 
02988                         {
02989                                 if ( COM_ParseFloat( &p, &f ) ) 
02990                                 {
02991                                         SkipRestOfLine( &p );
02992                                         continue;
02993                                 }
02994                                 //cap
02995                                 if ( f < 0.25f )
02996                                 {
02997                                         f = 0.25f;
02998                                 }
02999                                 NPC->client->saber[0].blade[7].radius = f;
03000                                 continue;
03001                         }
03002 
03003                         if ( !Q_stricmp( token, "saber2Radius" ) ) 
03004                         {
03005                                 if ( COM_ParseFloat( &p, &f ) ) 
03006                                 {
03007                                         SkipRestOfLine( &p );
03008                                         continue;
03009                                 }
03010                                 //cap
03011                                 if ( f < 0.25f )
03012                                 {
03013                                         f = 0.25f;
03014                                 }
03015                                 for ( n = 0; n < MAX_BLADES; n++ )
03016                                 {
03017                                         NPC->client->saber[1].blade[n].radius = f;
03018                                 }
03019                                 continue;
03020                         }
03021 
03022                         if ( !Q_stricmp( token, "saber2Radius2" ) ) 
03023                         {
03024                                 if ( COM_ParseFloat( &p, &f ) ) 
03025                                 {
03026                                         SkipRestOfLine( &p );
03027                                         continue;
03028                                 }
03029                                 //cap
03030                                 if ( f < 0.25f )
03031                                 {
03032                                         f = 0.25f;
03033                                 }
03034                                 NPC->client->saber[1].blade[1].radius = f;
03035                                 continue;
03036                         }
03037 
03038                         if ( !Q_stricmp( token, "saber2Radius3" ) ) 
03039                         {
03040                                 if ( COM_ParseFloat( &p, &f ) ) 
03041                                 {
03042                                         SkipRestOfLine( &p );
03043                                         continue;
03044                                 }
03045                                 //cap
03046                                 if ( f < 0.25f )
03047                                 {
03048                                         f = 0.25f;
03049                                 }
03050                                 NPC->client->saber[1].blade[2].radius = f;
03051                                 continue;
03052                         }
03053 
03054                         if ( !Q_stricmp( token, "saber2Radius4" ) ) 
03055                         {
03056                                 if ( COM_ParseFloat( &p, &f ) ) 
03057                                 {
03058                                         SkipRestOfLine( &p );
03059                                         continue;
03060                                 }
03061                                 //cap
03062                                 if ( f < 0.25f )
03063                                 {
03064                                         f = 0.25f;
03065                                 }
03066                                 NPC->client->saber[1].blade[3].radius = f;
03067                                 continue;
03068                         }
03069 
03070                         if ( !Q_stricmp( token, "saber2Radius5" ) ) 
03071                         {
03072                                 if ( COM_ParseFloat( &p, &f ) ) 
03073                                 {
03074                                         SkipRestOfLine( &p );
03075                                         continue;
03076                                 }
03077                                 //cap
03078                                 if ( f < 0.25f )
03079                                 {
03080                                         f = 0.25f;
03081                                 }
03082                                 NPC->client->saber[1].blade[4].radius = f;
03083                                 continue;
03084                         }
03085 
03086                         if ( !Q_stricmp( token, "saber2Radius6" ) ) 
03087                         {
03088                                 if ( COM_ParseFloat( &p, &f ) ) 
03089                                 {
03090                                         SkipRestOfLine( &p );
03091                                         continue;
03092                                 }
03093                                 //cap
03094                                 if ( f < 0.25f )
03095                                 {
03096                                         f = 0.25f;
03097                                 }
03098                                 NPC->client->saber[1].blade[5].radius = f;
03099                                 continue;
03100                         }
03101 
03102                         if ( !Q_stricmp( token, "saber2Radius7" ) ) 
03103                         {
03104                                 if ( COM_ParseFloat( &p, &f ) ) 
03105                                 {
03106                                         SkipRestOfLine( &p );
03107                                         continue;
03108                                 }
03109                                 //cap
03110                                 if ( f < 0.25f )
03111                                 {
03112                                         f = 0.25f;
03113                                 }
03114                                 NPC->client->saber[1].blade[6].radius = f;
03115                                 continue;
03116                         }
03117 
03118                         if ( !Q_stricmp( token, "saber2Radius8" ) ) 
03119                         {
03120                                 if ( COM_ParseFloat( &p, &f ) ) 
03121                                 {
03122                                         SkipRestOfLine( &p );
03123                                         continue;
03124                                 }
03125                                 //cap
03126                                 if ( f < 0.25f )
03127                                 {
03128                                         f = 0.25f;
03129                                 }
03130                                 NPC->client->saber[1].blade[7].radius = f;
03131                                 continue;
03132                         }
03133 
03134                         //ADD:
03135                         //saber sounds (on, off, loop)
03136                         //loop sound (like Vader's breathing or droid bleeps, etc.)
03137 
03138                         //starting saber style
03139                         if ( !Q_stricmp( token, "saberStyle" ) ) 
03140                         {
03141                                 if ( COM_ParseInt( &p, &n ) ) 
03142                                 {
03143                                         SkipRestOfLine( &p );
03144                                         continue;
03145                                 }
03146                                 //cap
03147                                 if ( n < 0 )
03148                                 {
03149                                         n = 0;
03150                                 }
03151                                 else if ( n > 5 )
03152                                 {
03153                                         n = 5;
03154                                 }
03155                                 NPC->client->ps.fd.saberAnimLevel = n;
03156                                 /*
03157                                 if ( parsingPlayer )
03158                                 {
03159                                         cg.saberAnimLevelPending = n;
03160                                 }
03161                                 */
03162                                 continue;
03163                         }
03164 
03165                         if ( !parsingPlayer )
03166                         {
03167                                 Com_Printf( "WARNING: unknown keyword '%s' while parsing '%s'\n", token, NPCName );
03168                         }
03169                         SkipRestOfLine( &p );
03170                 }
03171         }
03172 
03173 /*
03174 Ghoul2 Insert Start
03175 */
03176         if ( !md3Model )
03177         {
03178                 qboolean setTypeBack = qfalse;
03179 
03180                 if (npcSaber1 == 0)
03181                 { //use "kyle" for a default then
03182                         npcSaber1 = G_ModelIndex("@Kyle");
03183                         WP_SaberParseParms( "Kyle", &NPC->client->saber[0] );
03184                 }
03185 
03186                 NPC->s.npcSaber1 = npcSaber1;
03187                 NPC->s.npcSaber2 = npcSaber2;
03188 
03189                 if (!customSkin[0])
03190                 {
03191                         strcpy(customSkin, "default");
03192                 }
03193 
03194                 if ( NPC->client && NPC->client->NPC_class == CLASS_VEHICLE )
03195                 { //vehicles want their names fed in as models
03196                         //we put the $ in front to indicate a name and not a model
03197                         strcpy(playerModel, va("$%s", NPCName));
03198                 }
03199                 SetupGameGhoul2Model(NPC, playerModel, customSkin);
03200 
03201                 if (!NPC->NPC_type)
03202                 { //just do this for now so NPC_Precache can see the name.
03203                         NPC->NPC_type = (char *)NPCName;
03204                         setTypeBack = qtrue;
03205                 }
03206 
03207                 NPC_Precache(NPC); //this will just soundindex some values for sounds on the client,
03208 
03209                 if (setTypeBack)
03210                 { //don't want this being set if we aren't ready yet.
03211                         NPC->NPC_type = NULL;
03212                 }
03213         }
03214         else
03215         {
03216                 Com_Printf("MD3 MODEL NPC'S ARE NOT SUPPORTED IN MP!\n");
03217                 return qfalse;
03218         }
03219 /*
03220 Ghoul2 Insert End
03221 */
03222         /*
03223         if(     NPCsPrecached )
03224         {//Spawning in after initial precache, our models are precached, we just need to set our clientInfo
03225                 CG_RegisterClientModels( NPC->s.number );
03226                 CG_RegisterNPCCustomSounds( ci );
03227                 CG_RegisterNPCEffects( NPC->client->playerTeam );
03228         }
03229         */
03230         //rwwFIXMEFIXME: Do something here I guess to properly precache stuff.
03231 
03232         return qtrue;
03233 }
03234 
03235 #ifdef _XBOX
03236 char *npcParseBuffer = NULL;
03237 #else
03238 char npcParseBuffer[MAX_NPC_DATA_SIZE];
03239 #endif
03240 
03241 void NPC_LoadParms( void ) 
03242 {
03243         int                     len, totallen, npcExtFNLen, mainBlockLen, fileCnt, i;
03244 //      const char      *filename = "ext_data/NPC2.cfg";
03245         char             *holdChar, *marker;
03246         char            npcExtensionListBuf[2048];                      //      The list of file names read in
03247         fileHandle_t f;
03248         len = 0;
03249 
03250         //remember where to store the next one
03251         totallen = mainBlockLen = len;
03252         marker = NPCParms+totallen;
03253         *marker = 0;
03254 
03255         //now load in the extra .npc extensions
03256         fileCnt = trap_FS_GetFileList("ext_data/NPCs", ".npc", npcExtensionListBuf, sizeof(npcExtensionListBuf) );
03257 
03258 #ifdef _XBOX
03259         npcParseBuffer = (char *) Z_Malloc(MAX_NPC_DATA_SIZE, TAG_TEMP_WORKSPACE, qfalse, 4);
03260 #endif
03261 
03262         holdChar = npcExtensionListBuf;
03263         for ( i = 0; i < fileCnt; i++, holdChar += npcExtFNLen + 1 ) 
03264         {
03265                 npcExtFNLen = strlen( holdChar );
03266 
03267 //              Com_Printf( "Parsing %s\n", holdChar );
03268 
03269                 len = trap_FS_FOpenFile(va( "ext_data/NPCs/%s", holdChar), &f, FS_READ);
03270 
03271                 if ( len == -1 ) 
03272                 {
03273                         Com_Printf( "error reading file\n" );
03274                 }
03275                 else
03276                 {
03277                         if ( totallen + len >= MAX_NPC_DATA_SIZE ) {
03278                                 G_Error( "NPC extensions (*.npc) are too large" );
03279                         }
03280                         trap_FS_Read(npcParseBuffer, len, f);
03281                         npcParseBuffer[len] = 0;
03282 
03283                         len = COM_Compress( npcParseBuffer );
03284 
03285                         strcat( marker, npcParseBuffer );
03286                         strcat(marker, "\n");
03287                         len++;
03288                         trap_FS_FCloseFile(f);
03289 
03290                         totallen += len;
03291                         marker = NPCParms+totallen;
03292                         //*marker = 0; //rww - make sure this is null or strcat will not append to the correct place
03293                         //rww  12/19/02-actually the probelm was npcParseBuffer not being nul-term'd, which could cause issues in the strcat too
03294                 }
03295         }
03296 
03297 #ifdef _XBOX
03298         Z_Free(npcParseBuffer);
03299         npcParseBuffer = NULL;
03300 #endif
03301 
03302 }