00001
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),
00017 ENUM2STRING(NPCTEAM_PLAYER),
00018 ENUM2STRING(NPCTEAM_ENEMY),
00019 ENUM2STRING(NPCTEAM_NEUTRAL),
00020 "", -1
00021 };
00022
00023
00024 stringID_table_t ClassTable[] =
00025 {
00026 ENUM2STRING(CLASS_NONE),
00027 ENUM2STRING(CLASS_ATST),
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),
00038 ENUM2STRING(CLASS_GRAN),
00039 ENUM2STRING(CLASS_HOWLER),
00040
00041 ENUM2STRING(CLASS_IMPERIAL),
00042 ENUM2STRING(CLASS_IMPWORKER),
00043 ENUM2STRING(CLASS_INTERROGATOR),
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),
00051 ENUM2STRING(CLASS_MARK2),
00052 ENUM2STRING(CLASS_GALAKMECH),
00053 ENUM2STRING(CLASS_MINEMONSTER),
00054 ENUM2STRING(CLASS_MONMOTHA),
00055 ENUM2STRING(CLASS_MORGANKATARN),
00056 ENUM2STRING(CLASS_MOUSE),
00057 ENUM2STRING(CLASS_MURJJ),
00058 ENUM2STRING(CLASS_PRISONER),
00059 ENUM2STRING(CLASS_PROBE),
00060 ENUM2STRING(CLASS_PROTOCOL),
00061 ENUM2STRING(CLASS_R2D2),
00062 ENUM2STRING(CLASS_R5D2),
00063 ENUM2STRING(CLASS_REBEL),
00064 ENUM2STRING(CLASS_REBORN),
00065 ENUM2STRING(CLASS_REELO),
00066 ENUM2STRING(CLASS_REMOTE),
00067 ENUM2STRING(CLASS_RODIAN),
00068 ENUM2STRING(CLASS_SEEKER),
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
00081
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),
00091 ENUM2STRING(BS_ADVANCE_FIGHT),
00092 ENUM2STRING(BS_SLEEP),
00093 ENUM2STRING(BS_FOLLOW_LEADER),
00094 ENUM2STRING(BS_JUMP),
00095 ENUM2STRING(BS_SEARCH),
00096 ENUM2STRING(BS_WANDER),
00097 ENUM2STRING(BS_NOCLIP),
00098 ENUM2STRING(BS_REMOVE),
00099 ENUM2STRING(BS_CINEMATIC),
00100
00101 "", -1,
00102 };
00103
00104 #define stringIDExpand(str, strEnum) str, strEnum, ENUM2STRING(strEnum)
00105
00106 stringID_table_t BSETTable[] =
00107 {
00108 ENUM2STRING(BSET_SPAWN),
00109 ENUM2STRING(BSET_USE),
00110 ENUM2STRING(BSET_AWAKE),
00111 ENUM2STRING(BSET_ANGER),
00112 ENUM2STRING(BSET_ATTACK),
00113 ENUM2STRING(BSET_VICTORY),
00114 ENUM2STRING(BSET_LOSTENEMY),
00115 ENUM2STRING(BSET_PAIN),
00116 ENUM2STRING(BSET_FLEE),
00117 ENUM2STRING(BSET_DEATH),
00118 ENUM2STRING(BSET_DELAYED),
00119 ENUM2STRING(BSET_BLOCKED),
00120 ENUM2STRING(BSET_BUMPED),
00121 ENUM2STRING(BSET_STUCK),
00122 ENUM2STRING(BSET_FFIRE),
00123 ENUM2STRING(BSET_FFDEATH),
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
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 "player",
00151 "enemy",
00152 "neutral"
00153 };
00154
00155
00156 char *ClassNames[CLASS_NUM_CLASSES] =
00157 {
00158 "",
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
00218
00219
00220 int NPC_ReactionTime ( void )
00221 {
00222 return 200 * ( 6 - NPCInfo->stats.reactions );
00223 }
00224
00225
00226
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
00235
00236 #define MAX_NPC_DATA_SIZE 0x20000
00237 char NPCParms[MAX_NPC_DATA_SIZE];
00238 char NPCFile[MAX_QPATH];
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
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
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
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
00428
00429 if (*animFileIndex == -1)
00430 {
00431 return qfalse;
00432 }
00433
00434
00435
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 {
00450 return;
00451 }
00452
00453 p = NPCParms;
00454 COM_BeginParseSession(NPCFile);
00455
00456
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
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
00497 if ( !Q_stricmp( token, "legsmodel" ) )
00498 {
00499 if ( COM_ParseString( &p, &value ) )
00500 {
00501 continue;
00502 }
00503
00504 Q_strncpyz( filename, value, sizeof( filename ) );
00505 G_ParseAnimFileSet( filename, filename, &junk );
00506 return;
00507 }
00508
00509
00510 if ( !Q_stricmp( token, "playerModel" ) )
00511 {
00512 if ( COM_ParseString( &p, &value ) )
00513 {
00514 continue;
00515 }
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
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)) );
00572 CG_RegisterItemSounds( (item-bg_itemlist) );
00573 CG_RegisterItemVisuals( (item-bg_itemlist) );
00574
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");
00582 if (!spot) {
00583 strcat (weaponModel, "_w");
00584 }
00585 strcat (weaponModel, ".glm");
00586 }
00587 gi.G2API_PrecacheGhoul2Model( weaponModel );
00588 }
00589 }
00590 #endif
00591 }
00592
00593
00594
00595
00596
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 {
00613 return;
00614 }
00615 strcpy(customSkin,"default");
00616
00617 p = NPCParms;
00618 COM_BeginParseSession(NPCFile);
00619
00620
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
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
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
00674 }
00675 md3Model = qtrue;
00676 continue;
00677 }
00678
00679
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
00693 }
00694 md3Model = qtrue;
00695 continue;
00696 }
00697
00698
00699 if ( !Q_stricmp( token, "legsmodel" ) )
00700 {
00701 if ( COM_ParseString( &p, &value ) )
00702 {
00703 continue;
00704 }
00705
00706 md3Model = qtrue;
00707 continue;
00708 }
00709
00710
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
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
00734 if ( !Q_stricmp( token, "playerTeam" ) )
00735 {
00736 char tk[4096];
00737
00738 if ( COM_ParseString( &p, &value ) )
00739 {
00740 continue;
00741 }
00742
00743 Com_sprintf(tk, sizeof(tk), "NPC%s", token);
00744 playerTeam = (team_t)GetIDForString( TeamTable, tk );
00745 continue;
00746 }
00747
00748
00749
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
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
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
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
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
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
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
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
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 {
00853
00854 char modelName[MAX_QPATH];
00855
00856 Com_sprintf(modelName, sizeof(modelName), "models/players/%s/model.glm", playerModel);
00857 if (customSkin[0])
00858 {
00859 strcat( modelName, va("*%s", customSkin) );
00860 }
00861
00862 G_ModelIndex(modelName);
00863 }
00864 }
00865
00866
00867 NPC_PrecacheWeapons( playerTeam, spawner->spawnflags, spawner->NPC_type );
00868
00869
00870
00871
00872
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:
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);
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:
00926 case 2:
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
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
00967 NPC->NPC->rank = RANK_CREWMAN;
00968 NPC->client->playerTeam = NPC->s.teamowner = TEAM_PLAYER;
00969 NPC->client->clientInfo.customBasicSoundDir = "kyle";
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 {
01007 parsingPlayer = qtrue;
01008 }
01009
01010 if ( NPC->NPC )
01011 {
01012 stats = &NPC->NPC->stats;
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
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;
01042 }
01043 else
01044 {
01045 stats = NULL;
01046 }
01047
01048
01049
01050
01051
01052
01053
01054
01055 memset( (char *)surfOff, 0, sizeof(surfOff) );
01056 memset( (char *)surfOn, 0, sizeof(surfOn) );
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
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
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
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 {
01103
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
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
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
01155
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
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
01205 ri->headYawRangeLeft =
01206 ri->headYawRangeRight =
01207 ri->headPitchRangeUp =
01208 ri->headPitchRangeDown = 0;
01209 }
01210 continue;
01211 }
01212
01213
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
01224 ri->torsoYawRangeLeft =
01225 ri->torsoYawRangeRight =
01226 ri->torsoPitchRangeUp =
01227 ri->torsoPitchRangeDown = 0;
01228 }
01229 continue;
01230 }
01231
01232
01233 if ( !Q_stricmp( token, "legsmodel" ) )
01234 {
01235 if ( COM_ParseString( &p, &value ) )
01236 {
01237 continue;
01238 }
01239
01240
01241
01242
01243
01244 continue;
01245 }
01246
01247
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
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
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
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
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
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
01343 if ( !Q_stricmp( token, "headPitchRangeUp" ) )
01344 {
01345 if ( COM_ParseInt( &p, &n ) )
01346 {
01347