00001
00002
00003
00004 #include "cg_local.h"
00005 #include "..\ghoul2\g2.h"
00006 #include "bg_saga.h"
00007
00008 extern vmCvar_t cg_thirdPersonAlpha;
00009
00010 extern int cgSiegeTeam1PlShader;
00011 extern int cgSiegeTeam2PlShader;
00012
00013 extern void CG_AddRadarEnt(centity_t *cent);
00014 extern void CG_AddBracketedEnt(centity_t *cent);
00015 extern qboolean CG_InFighter( void );
00016 extern qboolean WP_SaberBladeUseSecondBladeStyle( saberInfo_t *saber, int bladeNum );
00017
00018
00019
00020 #define TURN_ON 0x00000000
00021 #define TURN_OFF 0x00000100
00022
00023 extern stringID_table_t animTable [MAX_ANIMATIONS+1];
00024
00025 char *cg_customSoundNames[MAX_CUSTOM_SOUNDS] = {
00026 "*death1",
00027 "*death2",
00028 "*death3",
00029 "*jump1",
00030 "*pain25",
00031 "*pain50",
00032 "*pain75",
00033 "*pain100",
00034 "*falling1",
00035 "*choke1",
00036 "*choke2",
00037 "*choke3",
00038 "*gasp",
00039 "*land1",
00040 "*taunt",
00041 NULL
00042 };
00043
00044
00045
00046
00047 const char *cg_customCombatSoundNames[MAX_CUSTOM_COMBAT_SOUNDS] =
00048 {
00049 "*anger1",
00050 "*anger2",
00051 "*anger3",
00052 "*victory1",
00053 "*victory2",
00054 "*victory3",
00055 "*confuse1",
00056 "*confuse2",
00057 "*confuse3",
00058 "*pushed1",
00059 "*pushed2",
00060 "*pushed3",
00061 "*choke1",
00062 "*choke2",
00063 "*choke3",
00064 "*ffwarn",
00065 "*ffturn",
00066 NULL
00067 };
00068
00069
00070
00071 const char *cg_customExtraSoundNames[MAX_CUSTOM_EXTRA_SOUNDS] =
00072 {
00073 "*chase1",
00074 "*chase2",
00075 "*chase3",
00076 "*cover1",
00077 "*cover2",
00078 "*cover3",
00079 "*cover4",
00080 "*cover5",
00081 "*detected1",
00082 "*detected2",
00083 "*detected3",
00084 "*detected4",
00085 "*detected5",
00086 "*lost1",
00087 "*outflank1",
00088 "*outflank2",
00089 "*escaping1",
00090 "*escaping2",
00091 "*escaping3",
00092 "*giveup1",
00093 "*giveup2",
00094 "*giveup3",
00095 "*giveup4",
00096 "*look1",
00097 "*look2",
00098 "*sight1",
00099 "*sight2",
00100 "*sight3",
00101 "*sound1",
00102 "*sound2",
00103 "*sound3",
00104 "*suspicious1",
00105 "*suspicious2",
00106 "*suspicious3",
00107 "*suspicious4",
00108 "*suspicious5",
00109 NULL
00110 };
00111
00112
00113
00114 const char *cg_customJediSoundNames[MAX_CUSTOM_JEDI_SOUNDS] =
00115 {
00116 "*combat1",
00117 "*combat2",
00118 "*combat3",
00119 "*jdetected1",
00120 "*jdetected2",
00121 "*jdetected3",
00122 "*taunt1",
00123 "*taunt2",
00124 "*taunt3",
00125 "*jchase1",
00126 "*jchase2",
00127 "*jchase3",
00128 "*jlost1",
00129 "*jlost2",
00130 "*jlost3",
00131 "*deflect1",
00132 "*deflect2",
00133 "*deflect3",
00134 "*gloat1",
00135 "*gloat2",
00136 "*gloat3",
00137 "*pushfail",
00138 NULL
00139 };
00140
00141
00142 const char *cg_customDuelSoundNames[MAX_CUSTOM_DUEL_SOUNDS] =
00143 {
00144 "*anger1",
00145 "*anger2",
00146 "*anger3",
00147 "*victory1",
00148 "*victory2",
00149 "*victory3",
00150 "*taunt1",
00151 "*taunt2",
00152 "*taunt3",
00153 "*deflect1",
00154 "*deflect2",
00155 "*deflect3",
00156 "*gloat1",
00157 "*gloat2",
00158 "*gloat3",
00159 NULL
00160 };
00161
00162 void CG_Disintegration(centity_t *cent, refEntity_t *ent);
00163
00164
00165
00166
00167
00168
00169
00170 sfxHandle_t CG_CustomSound( int clientNum, const char *soundName ) {
00171 clientInfo_t *ci;
00172 int i;
00173 int numCSounds = 0;
00174 int numCComSounds = 0;
00175 int numCExSounds = 0;
00176 int numCJediSounds = 0;
00177 int numCSiegeSounds = 0;
00178 int numCDuelSounds = 0;
00179 char lSoundName[MAX_QPATH];
00180
00181 if ( soundName[0] != '*' ) {
00182 return trap_S_RegisterSound( soundName );
00183 }
00184
00185 COM_StripExtension(soundName, lSoundName);
00186
00187 if ( clientNum < 0 )
00188 {
00189 clientNum = 0;
00190 }
00191
00192 if (clientNum >= MAX_CLIENTS)
00193 {
00194 ci = cg_entities[clientNum].npcClient;
00195 }
00196 else
00197 {
00198 ci = &cgs.clientinfo[ clientNum ];
00199 }
00200
00201 if (!ci)
00202 {
00203 return 0;
00204 }
00205
00206 for (i = 0; i < MAX_CUSTOM_SOUNDS; i++)
00207 {
00208 if (!cg_customSoundNames[i])
00209 {
00210 numCSounds = i;
00211 break;
00212 }
00213 }
00214
00215 if (clientNum >= MAX_CLIENTS)
00216 {
00217 for (i = 0; i < MAX_CUSTOM_SOUNDS; i++)
00218 {
00219 if (!cg_customCombatSoundNames[i])
00220 {
00221 numCComSounds = i;
00222 break;
00223 }
00224 }
00225
00226 for (i = 0; i < MAX_CUSTOM_SOUNDS; i++)
00227 {
00228 if (!cg_customExtraSoundNames[i])
00229 {
00230 numCExSounds = i;
00231 break;
00232 }
00233 }
00234
00235 for (i = 0; i < MAX_CUSTOM_SOUNDS; i++)
00236 {
00237 if (!cg_customJediSoundNames[i])
00238 {
00239 numCJediSounds = i;
00240 break;
00241 }
00242 }
00243 }
00244
00245 if (cgs.gametype >= GT_TEAM || cg_buildScript.integer)
00246 {
00247 for (i = 0; i < MAX_CUSTOM_SOUNDS; i++)
00248 {
00249 if (!bg_customSiegeSoundNames[i])
00250 {
00251 numCSiegeSounds = i;
00252 break;
00253 }
00254 }
00255 }
00256
00257 if (cgs.gametype == GT_DUEL
00258 || cgs.gametype == GT_POWERDUEL
00259 || cg_buildScript.integer)
00260 {
00261 for (i = 0; i < MAX_CUSTOM_SOUNDS; i++)
00262 {
00263 if (!cg_customDuelSoundNames[i])
00264 {
00265 numCDuelSounds = i;
00266 break;
00267 }
00268 }
00269 }
00270
00271 for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i++ )
00272 {
00273 if ( i < numCSounds && !strcmp( lSoundName, cg_customSoundNames[i] ) )
00274 {
00275 return ci->sounds[i];
00276 }
00277 else if ( (cgs.gametype >= GT_TEAM || cg_buildScript.integer) && i < numCSiegeSounds && !strcmp( lSoundName, bg_customSiegeSoundNames[i] ) )
00278 {
00279 return ci->siegeSounds[i];
00280 }
00281 else if ( (cgs.gametype == GT_DUEL || cgs.gametype == GT_POWERDUEL || cg_buildScript.integer) && i < numCDuelSounds && !strcmp( lSoundName, cg_customDuelSoundNames[i] ) )
00282 {
00283 return ci->duelSounds[i];
00284 }
00285 else if ( clientNum >= MAX_CLIENTS && i < numCComSounds && !strcmp( lSoundName, cg_customCombatSoundNames[i] ) )
00286 {
00287 return ci->combatSounds[i];
00288 }
00289 else if ( clientNum >= MAX_CLIENTS && i < numCExSounds && !strcmp( lSoundName, cg_customExtraSoundNames[i] ) )
00290 {
00291 return ci->extraSounds[i];
00292 }
00293 else if ( clientNum >= MAX_CLIENTS && i < numCJediSounds && !strcmp( lSoundName, cg_customJediSoundNames[i] ) )
00294 {
00295 return ci->jediSounds[i];
00296 }
00297 }
00298
00299
00300 #ifndef FINAL_BUILD
00301 Com_Printf( "Unknown custom sound: %s", lSoundName );
00302 #endif
00303 return 0;
00304 }
00305
00306
00307
00308
00309
00310
00311
00312
00313 #define MAX_SURF_LIST_SIZE 1024
00314 qboolean CG_ParseSurfsFile( const char *modelName, const char *skinName, char *surfOff, char *surfOn )
00315 {
00316 const char *text_p;
00317 int len;
00318 const char *token;
00319 const char *value;
00320 char text[20000];
00321 char sfilename[MAX_QPATH];
00322 fileHandle_t f;
00323 int i = 0;
00324
00325 while (skinName && skinName[i])
00326 {
00327 if (skinName[i] == '|')
00328 {
00329 return qfalse;
00330 }
00331
00332 i++;
00333 }
00334
00335
00336
00337 Com_sprintf( sfilename, sizeof( sfilename ), "models/players/%s/model_%s.surf", modelName, skinName );
00338
00339
00340 len = trap_FS_FOpenFile( sfilename, &f, FS_READ );
00341 if ( len <= 0 )
00342 {
00343 return qfalse;
00344 }
00345 if ( len >= sizeof( text ) - 1 )
00346 {
00347 Com_Printf( "File %s too long\n", sfilename );
00348 return qfalse;
00349 }
00350
00351 trap_FS_Read( text, len, f );
00352 text[len] = 0;
00353 trap_FS_FCloseFile( f );
00354
00355
00356 text_p = text;
00357
00358 memset( (char *)surfOff, 0, sizeof(surfOff) );
00359 memset( (char *)surfOn, 0, sizeof(surfOn) );
00360
00361
00362 while ( 1 )
00363 {
00364 token = COM_ParseExt( &text_p, qtrue );
00365 if ( !token || !token[0] )
00366 {
00367 break;
00368 }
00369
00370
00371 if ( !Q_stricmp( token, "surfOff" ) )
00372 {
00373 if ( COM_ParseString( &text_p, &value ) )
00374 {
00375 continue;
00376 }
00377 if ( surfOff && surfOff[0] )
00378 {
00379 Q_strcat( surfOff, MAX_SURF_LIST_SIZE, "," );
00380 Q_strcat( surfOff, MAX_SURF_LIST_SIZE, value );
00381 }
00382 else
00383 {
00384 Q_strncpyz( surfOff, value, MAX_SURF_LIST_SIZE );
00385 }
00386 continue;
00387 }
00388
00389
00390 if ( !Q_stricmp( token, "surfOn" ) )
00391 {
00392 if ( COM_ParseString( &text_p, &value ) )
00393 {
00394 continue;
00395 }
00396 if ( surfOn && surfOn[0] )
00397 {
00398 Q_strcat( surfOn, MAX_SURF_LIST_SIZE, ",");
00399 Q_strcat( surfOn, MAX_SURF_LIST_SIZE, value );
00400 }
00401 else
00402 {
00403 Q_strncpyz( surfOn, value, MAX_SURF_LIST_SIZE );
00404 }
00405 continue;
00406 }
00407 }
00408 return qtrue;
00409 }
00410
00411
00412
00413
00414
00415
00416 #include "../namespace_begin.h"
00417 qboolean BG_IsValidCharacterModel(const char *modelName, const char *skinName);
00418 qboolean BG_ValidateSkinForTeam( const char *modelName, char *skinName, int team, float *colors );
00419 #include "../namespace_end.h"
00420
00421 static qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *modelName, const char *skinName, const char *teamName, int clientNum ) {
00422 int handle;
00423 char afilename[MAX_QPATH];
00424 char *slash;
00425 char GLAName[MAX_QPATH];
00426 vec3_t tempVec = {0,0,0};
00427 qboolean badModel = qfalse;
00428 char surfOff[MAX_SURF_LIST_SIZE];
00429 char surfOn[MAX_SURF_LIST_SIZE];
00430 int checkSkin;
00431 char *useSkinName;
00432
00433 retryModel:
00434 if (badModel)
00435 {
00436 if (modelName && modelName[0])
00437 {
00438 Com_Printf("WARNING: Attempted to load an unsupported multiplayer model %s! (bad or missing bone, or missing animation sequence)\n", modelName);
00439 }
00440
00441 modelName = "kyle";
00442 skinName = "default";
00443
00444 badModel = qfalse;
00445 }
00446
00447
00448 if (ci->ghoul2Model && trap_G2_HaveWeGhoul2Models(ci->ghoul2Model))
00449 {
00450 trap_G2API_CleanGhoul2Models(&(ci->ghoul2Model));
00451 }
00452
00453 if (!BG_IsValidCharacterModel(modelName, skinName))
00454 {
00455 modelName = "kyle";
00456 skinName = "default";
00457 }
00458
00459 if ( cgs.gametype >= GT_TEAM && !cgs.jediVmerc && cgs.gametype != GT_SIEGE )
00460 {
00461 BG_ValidateSkinForTeam( ci->modelName, ci->skinName, ci->team, ci->colorOverride );
00462 skinName = ci->skinName;
00463 }
00464 else
00465 {
00466 ci->colorOverride[0] = ci->colorOverride[1] = ci->colorOverride[2] = 0.0f;
00467 }
00468
00469 if (strchr(skinName, '|'))
00470 {
00471 useSkinName = va("models/players/%s/|%s", modelName, skinName);
00472 }
00473 else
00474 {
00475 useSkinName = va("models/players/%s/model_%s.skin", modelName, skinName);
00476 }
00477
00478 checkSkin = trap_R_RegisterSkin(useSkinName);
00479
00480 if (checkSkin)
00481 {
00482 ci->torsoSkin = checkSkin;
00483 }
00484 else
00485 {
00486 ci->torsoSkin = trap_R_RegisterSkin(va("models/players/%s/model_default.skin", modelName, skinName));
00487 }
00488 Com_sprintf( afilename, sizeof( afilename ), "models/players/%s/model.glm", modelName );
00489 handle = trap_G2API_InitGhoul2Model(&ci->ghoul2Model, afilename, 0, ci->torsoSkin, 0, 0, 0);
00490
00491 if (handle<0)
00492 {
00493 return qfalse;
00494 }
00495
00496
00497
00498 trap_G2API_SetSkin(ci->ghoul2Model, 0, ci->torsoSkin, ci->torsoSkin);
00499
00500 GLAName[0] = 0;
00501
00502 trap_G2API_GetGLAName( ci->ghoul2Model, 0, GLAName);
00503 if (GLAName[0] != 0)
00504 {
00505 if (!strstr(GLAName, "players/_humanoid/")
00506 )
00507 {
00508 badModel = qtrue;
00509 goto retryModel;
00510 }
00511 }
00512
00513 if (!BGPAFtextLoaded)
00514 {
00515 if (GLAName[0] == 0)
00516 {
00517 badModel = qtrue;
00518 goto retryModel;
00519 }
00520 Q_strncpyz( afilename, GLAName, sizeof( afilename ));
00521 slash = Q_strrchr( afilename, '/' );
00522 if ( slash )
00523 {
00524 strcpy(slash, "/animation.cfg");
00525 }
00526 else
00527 {
00528 return qfalse;
00529 }
00530
00531
00532 if (Q_stricmp(afilename, "models/players/_humanoid/animation.cfg")
00533 )
00534 {
00535 Com_Printf( "Model does not use supported animation config.\n");
00536 return qfalse;
00537 }
00538 else if (BG_ParseAnimationFile("models/players/_humanoid/animation.cfg", bgHumanoidAnimations, qtrue) == -1)
00539 {
00540 Com_Printf( "Failed to load animation file models/players/_humanoid/animation.cfg\n" );
00541 return qfalse;
00542 }
00543
00544 BG_ParseAnimationEvtFile( "models/players/_humanoid/", 0, -1 );
00545
00546
00547
00548
00549
00550
00551
00552
00553 }
00554 else if (!bgAllEvents[0].eventsParsed)
00555 {
00556 BG_ParseAnimationEvtFile( "models/players/_humanoid/", 0, -1 );
00557
00558
00559
00560
00561 }
00562
00563 if ( CG_ParseSurfsFile( modelName, skinName, surfOff, surfOn ) )
00564 {
00565 const char *token;
00566 const char *p;
00567
00568
00569 if ( surfOff && surfOff[0] )
00570 {
00571 p = surfOff;
00572 while ( 1 )
00573 {
00574 token = COM_ParseExt( &p, qtrue );
00575 if ( !token[0] )
00576 {
00577 break;
00578 }
00579
00580 trap_G2API_SetSurfaceOnOff( ci->ghoul2Model, token, 0x00000002 );
00581 }
00582 }
00583 if ( surfOn && surfOn[0] )
00584 {
00585 p = surfOn;
00586 while ( 1 )
00587 {
00588 token = COM_ParseExt( &p, qtrue );
00589 if ( !token[0] )
00590 {
00591 break;
00592 }
00593
00594 trap_G2API_SetSurfaceOnOff( ci->ghoul2Model, token, 0 );
00595 }
00596 }
00597 }
00598
00599
00600 ci->bolt_rhand = trap_G2API_AddBolt(ci->ghoul2Model, 0, "*r_hand");
00601
00602 if (!trap_G2API_SetBoneAnim(ci->ghoul2Model, 0, "model_root", 0, 12, BONE_ANIM_OVERRIDE_LOOP, 1.0f, cg.time, -1, -1))
00603 {
00604 badModel = qtrue;
00605 }
00606
00607 if (!trap_G2API_SetBoneAngles(ci->ghoul2Model, 0, "upper_lumbar", tempVec, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL, 0, cg.time))
00608 {
00609 badModel = qtrue;
00610 }
00611
00612 if (!trap_G2API_SetBoneAngles(ci->ghoul2Model, 0, "cranium", tempVec, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_Y, POSITIVE_X, NULL, 0, cg.time))
00613 {
00614 badModel = qtrue;
00615 }
00616
00617 ci->bolt_lhand = trap_G2API_AddBolt(ci->ghoul2Model, 0, "*l_hand");
00618
00619
00620
00621 trap_G2API_AddBolt(ci->ghoul2Model, 0, "*chestg");
00622
00623
00624 trap_G2API_AddBolt(ci->ghoul2Model, 0, "*r_hand_cap_r_arm");
00625 trap_G2API_AddBolt(ci->ghoul2Model, 0, "*l_hand_cap_l_arm");
00626
00627 ci->bolt_head = trap_G2API_AddBolt(ci->ghoul2Model, 0, "*head_top");
00628 if (ci->bolt_head == -1)
00629 {
00630 ci->bolt_head = trap_G2API_AddBolt(ci->ghoul2Model, 0, "ceyebrow");
00631 }
00632
00633 ci->bolt_motion = trap_G2API_AddBolt(ci->ghoul2Model, 0, "Motion");
00634
00635
00636 ci->bolt_llumbar = trap_G2API_AddBolt(ci->ghoul2Model, 0, "lower_lumbar");
00637
00638 if (ci->bolt_rhand == -1 || ci->bolt_lhand == -1 || ci->bolt_head == -1 || ci->bolt_motion == -1 || ci->bolt_llumbar == -1)
00639 {
00640 badModel = qtrue;
00641 }
00642
00643 if (badModel)
00644 {
00645 goto retryModel;
00646 }
00647
00648 if (!Q_stricmp(modelName, "boba_fett"))
00649 {
00650 trap_G2API_SetSurfaceOnOff(ci->ghoul2Model, "torso_rjet", TURN_OFF);
00651 trap_G2API_SetSurfaceOnOff(ci->ghoul2Model, "torso_cjet", TURN_OFF);
00652 trap_G2API_SetSurfaceOnOff(ci->ghoul2Model, "torso_ljet", TURN_OFF);
00653 }
00654
00655
00656
00657 if (clientNum != -1)
00658 {
00659
00660
00661
00662
00663
00664
00665
00666
00667 cg_entities[clientNum].ghoul2weapon = NULL;
00668 }
00669
00670 Q_strncpyz (ci->teamName, teamName, sizeof(ci->teamName));
00671
00672
00673 ci->modelIcon = trap_R_RegisterShaderNoMip ( va ( "models/players/%s/icon_%s", modelName, skinName ) );
00674 if (!ci->modelIcon)
00675 {
00676 int i = 0;
00677 int j;
00678 char iconName[1024];
00679 strcpy(iconName, "icon_");
00680 j = strlen(iconName);
00681 while (skinName[i] && skinName[i] != '|' && j < 1024)
00682 {
00683 iconName[j] = skinName[i];
00684 j++;
00685 i++;
00686 }
00687 iconName[j] = 0;
00688 if (skinName[i] == '|')
00689 {
00690 ci->modelIcon = trap_R_RegisterShaderNoMip ( va ( "models/players/%s/%s", modelName, iconName ) );
00691 }
00692 }
00693 return qtrue;
00694 }
00695
00696
00697
00698
00699
00700
00701 static void CG_ColorFromString( const char *v, vec3_t color ) {
00702 int val;
00703
00704 VectorClear( color );
00705
00706 val = atoi( v );
00707
00708 if ( val < 1 || val > 7 ) {
00709 VectorSet( color, 1, 1, 1 );
00710 return;
00711 }
00712
00713 if ( val & 1 ) {
00714 color[2] = 1.0f;
00715 }
00716 if ( val & 2 ) {
00717 color[1] = 1.0f;
00718 }
00719 if ( val & 4 ) {
00720 color[0] = 1.0f;
00721 }
00722 }
00723
00724
00725
00726
00727
00728
00729 static void CG_ColorFromInt( int val, vec3_t color ) {
00730 VectorClear( color );
00731
00732 if ( val < 1 || val > 7 ) {
00733 VectorSet( color, 1, 1, 1 );
00734 return;
00735 }
00736
00737 if ( val & 1 ) {
00738 color[2] = 1.0f;
00739 }
00740 if ( val & 2 ) {
00741 color[1] = 1.0f;
00742 }
00743 if ( val & 4 ) {
00744 color[0] = 1.0f;
00745 }
00746 }
00747
00748
00749 int CG_G2SkelForModel(void *g2)
00750 {
00751 int animIndex = -1;
00752 char GLAName[MAX_QPATH];
00753 char *slash;
00754
00755 GLAName[0] = 0;
00756 trap_G2API_GetGLAName(g2, 0, GLAName);
00757
00758 slash = Q_strrchr( GLAName, '/' );
00759 if ( slash )
00760 {
00761 strcpy(slash, "/animation.cfg");
00762
00763 animIndex = BG_ParseAnimationFile(GLAName, NULL, qfalse);
00764 }
00765
00766 return animIndex;
00767 }
00768
00769
00770 int CG_G2EvIndexForModel(void *g2, int animIndex)
00771 {
00772 int evtIndex = -1;
00773 char GLAName[MAX_QPATH];
00774 char *slash;
00775
00776 if (animIndex == -1)
00777 {
00778 assert(!"shouldn't happen, bad animIndex");
00779 return -1;
00780 }
00781
00782 GLAName[0] = 0;
00783 trap_G2API_GetGLAName(g2, 0, GLAName);
00784
00785 slash = Q_strrchr( GLAName, '/' );
00786 if ( slash )
00787 {
00788 slash++;
00789 *slash = 0;
00790
00791 evtIndex = BG_ParseAnimationEvtFile(GLAName, animIndex, bgNumAnimEvents);
00792 }
00793
00794 return evtIndex;
00795 }
00796
00797 #define DEFAULT_FEMALE_SOUNDPATH "chars/mp_generic_female/misc"//"chars/tavion/misc"
00798 #define DEFAULT_MALE_SOUNDPATH "chars/mp_generic_male/misc"//"chars/kyle/misc"
00799 void CG_LoadCISounds(clientInfo_t *ci, qboolean modelloaded)
00800 {
00801 fileHandle_t f;
00802 qboolean isFemale = qfalse;
00803 int i = 0;
00804 int fLen = 0;
00805 const char *dir;
00806 char soundpath[MAX_QPATH];
00807 char soundName[1024];
00808 const char *s;
00809
00810 dir = ci->modelName;
00811
00812 if ( !ci->skinName || !Q_stricmp( "default", ci->skinName ) )
00813 {
00814 fLen = trap_FS_FOpenFile(va("models/players/%s/sounds.cfg", dir), &f, FS_READ);
00815 if ( !f )
00816 {
00817 fLen = trap_FS_FOpenFile(va("models/players/%s/sounds_default.cfg", dir), &f, FS_READ);
00818 }
00819 }
00820 else
00821 {
00822 fLen = trap_FS_FOpenFile(va("models/players/%s/sounds_%s.cfg", dir, ci->skinName), &f, FS_READ);
00823 if ( !f )
00824 {
00825 fLen = trap_FS_FOpenFile(va("models/players/%s/sounds.cfg", dir), &f, FS_READ);
00826 }
00827 }
00828
00829 soundpath[0] = 0;
00830
00831 if (f)
00832 {
00833 trap_FS_Read(soundpath, fLen, f);
00834 soundpath[fLen] = 0;
00835
00836 i = fLen;
00837
00838 while (i >= 0 && soundpath[i] != '\n')
00839 {
00840 if (soundpath[i] == 'f')
00841 {
00842 isFemale = qtrue;
00843 soundpath[i] = 0;
00844 }
00845
00846 i--;
00847 }
00848
00849 i = 0;
00850
00851 while (soundpath[i] && soundpath[i] != '\r' && soundpath[i] != '\n')
00852 {
00853 i++;
00854 }
00855 soundpath[i] = 0;
00856
00857 trap_FS_FCloseFile(f);
00858 }
00859
00860 if (isFemale)
00861 {
00862 ci->gender = GENDER_FEMALE;
00863 }
00864 else
00865 {
00866 ci->gender = GENDER_MALE;
00867 }
00868
00869 trap_S_ShutUp(qtrue);
00870
00871 for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i++ )
00872 {
00873 s = cg_customSoundNames[i];
00874 if ( !s ) {
00875 break;
00876 }
00877
00878 Com_sprintf(soundName, sizeof(soundName), "%s", s+1);
00879 COM_StripExtension(soundName, soundName);
00880
00881
00882 ci->sounds[i] = 0;
00883
00884 if (soundpath[0])
00885 {
00886 ci->sounds[i] = trap_S_RegisterSound( va("sound/chars/%s/misc/%s", soundpath, soundName) );
00887 }
00888 else
00889 {
00890 if (modelloaded)
00891 {
00892 ci->sounds[i] = trap_S_RegisterSound( va("sound/chars/%s/misc/%s", dir, soundName) );
00893 }
00894 }
00895
00896 if (!ci->sounds[i])
00897 {
00898 if (isFemale)
00899 {
00900 ci->sounds[i] = trap_S_RegisterSound( va("sound/%s/%s", DEFAULT_FEMALE_SOUNDPATH, soundName) );
00901 }
00902 else
00903 {
00904 ci->sounds[i] = trap_S_RegisterSound( va("sound/%s/%s", DEFAULT_MALE_SOUNDPATH, soundName) );
00905 }
00906 }
00907 }
00908
00909 if (cgs.gametype >= GT_TEAM || cg_buildScript.integer)
00910 {
00911 for ( i = 0 ; i < MAX_CUSTOM_SIEGE_SOUNDS; i++ )
00912 {
00913 s = bg_customSiegeSoundNames[i];
00914 if ( !s )
00915 {
00916 break;
00917 }
00918
00919 Com_sprintf(soundName, sizeof(soundName), "%s", s+1);
00920 COM_StripExtension(soundName, soundName);
00921
00922
00923 ci->siegeSounds[i] = 0;
00924
00925 if (soundpath[0])
00926 {
00927 ci->siegeSounds[i] = trap_S_RegisterSound( va("sound/%s/%s", soundpath, soundName) );
00928 }
00929 else
00930 {
00931 if (modelloaded)
00932 {
00933 ci->siegeSounds[i] = trap_S_RegisterSound( va("sound/chars/%s/misc/%s", dir, soundName) );
00934 }
00935 }
00936
00937 if (!ci->siegeSounds[i])
00938 {
00939 if (isFemale)
00940 {
00941 ci->siegeSounds[i] = trap_S_RegisterSound( va("sound/%s/%s", DEFAULT_FEMALE_SOUNDPATH, soundName) );
00942 }
00943 else
00944 {
00945 ci->siegeSounds[i] = trap_S_RegisterSound( va("sound/%s/%s", DEFAULT_MALE_SOUNDPATH, soundName) );
00946 }
00947 }
00948 }
00949 }
00950
00951 if (cgs.gametype == GT_DUEL
00952 ||cgs.gametype == GT_POWERDUEL
00953 || cg_buildScript.integer)
00954 {
00955 for ( i = 0 ; i < MAX_CUSTOM_DUEL_SOUNDS; i++ )
00956 {
00957 s = cg_customDuelSoundNames[i];
00958 if ( !s )
00959 {
00960 break;
00961 }
00962
00963 Com_sprintf(soundName, sizeof(soundName), "%s", s+1);
00964 COM_StripExtension(soundName, soundName);
00965
00966
00967 ci->duelSounds[i] = 0;
00968
00969 if (soundpath[0])
00970 {
00971 ci->duelSounds[i] = trap_S_RegisterSound( va("sound/chars/%s/misc/%s", soundpath, soundName) );
00972 }
00973 else
00974 {
00975 if (modelloaded)
00976 {
00977 ci->duelSounds[i] = trap_S_RegisterSound( va("sound/chars/%s/misc/%s", dir, soundName) );
00978 }
00979 }
00980
00981 if (!ci->duelSounds[i])
00982 {
00983 if (isFemale)
00984 {
00985 ci->duelSounds[i] = trap_S_RegisterSound( va("sound/%s/%s", DEFAULT_FEMALE_SOUNDPATH, soundName) );
00986 }
00987 else
00988 {
00989 ci->duelSounds[i] = trap_S_RegisterSound( va("sound/%s/%s", DEFAULT_MALE_SOUNDPATH, soundName) );
00990 }
00991 }
00992 }
00993 }
00994
00995 trap_S_ShutUp(qfalse);
00996 }
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006 void CG_LoadClientInfo( clientInfo_t *ci ) {
01007 qboolean modelloaded;
01008 int clientNum;
01009 int i;
01010 char teamname[MAX_QPATH];
01011
01012 clientNum = ci - cgs.clientinfo;
01013
01014 if (clientNum < 0 || clientNum >= MAX_CLIENTS)
01015 {
01016 clientNum = -1;
01017 }
01018
01019 ci->deferred = qfalse;
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043 teamname[0] = 0;
01044 if( cgs.gametype >= GT_TEAM) {
01045 if( ci->team == TEAM_BLUE ) {
01046 Q_strncpyz(teamname, DEFAULT_BLUETEAM_NAME, sizeof(teamname) );
01047 } else {
01048 Q_strncpyz(teamname, DEFAULT_REDTEAM_NAME, sizeof(teamname) );
01049 }
01050 }
01051 if( teamname[0] ) {
01052 strcat( teamname, "/" );
01053 }
01054 modelloaded = qtrue;
01055 if (cgs.gametype == GT_SIEGE &&
01056 (ci->team == TEAM_SPECTATOR || ci->siegeIndex == -1))
01057 {
01058 if ( !CG_RegisterClientModelname( ci, DEFAULT_MODEL, "default", teamname, -1 ) )
01059 {
01060 CG_Error( "DEFAULT_MODEL (%s) failed to register", DEFAULT_MODEL );
01061 }
01062 }
01063 else
01064 {
01065 if ( !CG_RegisterClientModelname( ci, ci->modelName, ci->skinName, teamname, clientNum ) ) {
01066
01067
01068
01069
01070
01071 if( cgs.gametype >= GT_TEAM) {
01072
01073 if( ci->team == TEAM_BLUE ) {
01074 Q_strncpyz(teamname, DEFAULT_BLUETEAM_NAME, sizeof(teamname) );
01075 } else {
01076 Q_strncpyz(teamname, DEFAULT_REDTEAM_NAME, sizeof(teamname) );
01077 }
01078 if ( !CG_RegisterClientModelname( ci, DEFAULT_MODEL, ci->skinName, teamname, -1 ) ) {
01079 CG_Error( "DEFAULT_MODEL / skin (%s/%s) failed to register", DEFAULT_MODEL, ci->skinName );
01080 }
01081 } else {
01082 if ( !CG_RegisterClientModelname( ci, DEFAULT_MODEL, "default", teamname, -1 ) ) {
01083 CG_Error( "DEFAULT_MODEL (%s) failed to register", DEFAULT_MODEL );
01084 }
01085 }
01086 modelloaded = qfalse;
01087 }
01088 }
01089
01090 if (clientNum != -1)
01091 {
01092 trap_G2API_ClearAttachedInstance(clientNum);
01093 }
01094
01095 if (clientNum != -1 && ci->ghoul2Model && trap_G2_HaveWeGhoul2Models(ci->ghoul2Model))
01096 {
01097 if (cg_entities[clientNum].ghoul2 && trap_G2_HaveWeGhoul2Models(cg_entities[clientNum].ghoul2))
01098 {
01099 trap_G2API_CleanGhoul2Models(&cg_entities[clientNum].ghoul2);
01100 }
01101 trap_G2API_DuplicateGhoul2Instance(ci->ghoul2Model, &cg_entities[clientNum].ghoul2);
01102
01103
01104
01105 trap_G2API_AttachInstanceToEntNum(cg_entities[clientNum].ghoul2, clientNum, qfalse);
01106
01107
01108 if (trap_G2API_AddBolt(cg_entities[clientNum].ghoul2, 0, "face") == -1)
01109 {
01110 cg_entities[clientNum].noFace = qtrue;
01111 }
01112
01113 cg_entities[clientNum].localAnimIndex = CG_G2SkelForModel(cg_entities[clientNum].ghoul2);
01114 cg_entities[clientNum].eventAnimIndex = CG_G2EvIndexForModel(cg_entities[clientNum].ghoul2, cg_entities[clientNum].localAnimIndex);
01115 }
01116
01117 ci->newAnims = qfalse;
01118 if ( ci->torsoModel ) {
01119 orientation_t tag;
01120
01121 if ( trap_R_LerpTag( &tag, ci->torsoModel, 0, 0, 1, "tag_flag" ) ) {
01122 ci->newAnims = qtrue;
01123 }
01124 }
01125
01126
01127 if (cgs.gametype == GT_SIEGE &&
01128 (ci->team == TEAM_SPECTATOR || ci->siegeIndex == -1))
01129 {
01130 }
01131 else
01132 {
01133 CG_LoadCISounds(ci, modelloaded);
01134 }
01135
01136 ci->deferred = qfalse;
01137
01138
01139
01140 clientNum = ci - cgs.clientinfo;
01141 for ( i = 0 ; i < MAX_GENTITIES ; i++ ) {
01142 if ( cg_entities[i].currentState.clientNum == clientNum
01143 && cg_entities[i].currentState.eType == ET_PLAYER ) {
01144 CG_ResetPlayerEntity( &cg_entities[i] );
01145 }
01146 }
01147 }
01148
01149
01150
01151 static void CG_InitG2SaberData(int saberNum, clientInfo_t *ci)
01152 {
01153 trap_G2API_InitGhoul2Model(&ci->ghoul2Weapons[saberNum], ci->saber[saberNum].model, 0, ci->saber[saberNum].skin, 0, 0, 0);
01154
01155 if (ci->ghoul2Weapons[saberNum])
01156 {
01157 int k = 0;
01158 int tagBolt;
01159 char *tagName;
01160
01161 if (ci->saber[saberNum].skin)
01162 {
01163 trap_G2API_SetSkin(ci->ghoul2Weapons[saberNum], 0, ci->saber[saberNum].skin, ci->saber[saberNum].skin);
01164 }
01165
01166 if (ci->saber[saberNum].saberFlags & SFL_BOLT_TO_WRIST)
01167 {
01168 trap_G2API_SetBoltInfo(ci->ghoul2Weapons[saberNum], 0, 3+saberNum);
01169 }
01170 else
01171 {
01172 trap_G2API_SetBoltInfo(ci->ghoul2Weapons[saberNum], 0, saberNum);
01173 }
01174
01175 while (k < ci->saber[saberNum].numBlades)
01176 {
01177 tagName = va("*blade%i", k+1);
01178 tagBolt = trap_G2API_AddBolt(ci->ghoul2Weapons[saberNum], 0, tagName);
01179
01180 if (tagBolt == -1)
01181 {
01182 if (k == 0)
01183 {
01184 tagBolt = trap_G2API_AddBolt(ci->ghoul2Weapons[saberNum], 0, "*flash");
01185
01186 if (tagBolt == -1)
01187 {
01188 assert(0);
01189 }
01190 break;
01191 }
01192
01193 if (tagBolt == -1)
01194 {
01195 assert(0);
01196 break;
01197 }
01198 }
01199
01200 k++;
01201 }
01202 }
01203 }
01204
01205
01206
01207
01208
01209
01210
01211 static void CG_CopyClientInfoModel( clientInfo_t *from, clientInfo_t *to )
01212 {
01213 VectorCopy( from->headOffset, to->headOffset );
01214
01215 to->gender = from->gender;
01216
01217 to->legsModel = from->legsModel;
01218 to->legsSkin = from->legsSkin;
01219 to->torsoModel = from->torsoModel;
01220 to->torsoSkin = from->torsoSkin;
01221
01222
01223 to->modelIcon = from->modelIcon;
01224
01225 to->newAnims = from->newAnims;
01226
01227
01228
01229 assert(to->ghoul2Model != from->ghoul2Model);
01230
01231 if (to->ghoul2Model && trap_G2_HaveWeGhoul2Models(to->ghoul2Model))
01232 {
01233 trap_G2API_CleanGhoul2Models(&to->ghoul2Model);
01234 }
01235 if (from->ghoul2Model && trap_G2_HaveWeGhoul2Models(from->ghoul2Model))
01236 {
01237 trap_G2API_DuplicateGhoul2Instance(from->ghoul2Model, &to->ghoul2Model);
01238 }
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270 to->bolt_head = from->bolt_head;
01271 to->bolt_lhand = from->bolt_lhand;
01272 to->bolt_rhand = from->bolt_rhand;
01273 to->bolt_motion = from->bolt_motion;
01274 to->bolt_llumbar = from->bolt_llumbar;
01275
01276 to->siegeIndex = from->siegeIndex;
01277
01278 memcpy( to->sounds, from->sounds, sizeof( to->sounds ) );
01279 memcpy( to->siegeSounds, from->siegeSounds, sizeof( to->siegeSounds ) );
01280 memcpy( to->duelSounds, from->duelSounds, sizeof( to->duelSounds ) );
01281 }
01282
01283
01284
01285
01286
01287
01288 static qboolean CG_ScanForExistingClientInfo( clientInfo_t *ci, int clientNum ) {
01289 int i;
01290 clientInfo_t *match;
01291
01292 for ( i = 0 ; i < cgs.maxclients ; i++ ) {
01293 match = &cgs.clientinfo[ i ];
01294 if ( !match->infoValid ) {
01295 continue;
01296 }
01297 if ( match->deferred ) {
01298 continue;
01299 }
01300 if ( !Q_stricmp( ci->modelName, match->modelName )
01301 && !Q_stricmp( ci->skinName, match->skinName )
01302 && !Q_stricmp( ci->saberName, match->saberName)
01303 && !Q_stricmp( ci->saber2Name, match->saber2Name)
01304
01305
01306
01307
01308 && (cgs.gametype < GT_TEAM || ci->team == match->team)
01309 && ci->siegeIndex == match->siegeIndex
01310 && match->ghoul2Model
01311 && match->bolt_head)
01312 {
01313
01314
01315 ci->deferred = qfalse;
01316
01317
01318
01319
01320
01321 if (clientNum == i)
01322 {
01323 if (match->ghoul2Model && trap_G2_HaveWeGhoul2Models(match->ghoul2Model))
01324 {
01325 if (ci->ghoul2Model && trap_G2_HaveWeGhoul2Models(ci->ghoul2Model))
01326 {
01327 trap_G2API_CleanGhoul2Models(&ci->ghoul2Model);
01328 }
01329
01330 VectorCopy( match->headOffset, ci->headOffset );
01331
01332 ci->gender = match->gender;
01333
01334 ci->legsModel = match->legsModel;
01335 ci->legsSkin = match->legsSkin;
01336 ci->torsoModel = match->torsoModel;
01337 ci->torsoSkin = match->torsoSkin;
01338 ci->modelIcon = match->modelIcon;
01339
01340 ci->newAnims = match->newAnims;
01341
01342 ci->bolt_head = match->bolt_head;
01343 ci->bolt_lhand = match->bolt_lhand;
01344 ci->bolt_rhand = match->bolt_rhand;
01345 ci->bolt_motion = match->bolt_motion;
01346 ci->bolt_llumbar = match->bolt_llumbar;
01347 ci->siegeIndex = match->siegeIndex;
01348
01349 memcpy( ci->sounds, match->sounds, sizeof( ci->sounds ) );
01350 memcpy( ci->siegeSounds, match->siegeSounds, sizeof( ci->siegeSounds ) );
01351 memcpy( ci->duelSounds, match->duelSounds, sizeof( ci->duelSounds ) );
01352
01353
01354
01355
01356 ci->ghoul2Model = match->ghoul2Model;
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374 }
01375 }
01376 else
01377 {
01378 CG_CopyClientInfoModel( match, ci );
01379 }
01380
01381 return qtrue;
01382 }
01383 }
01384
01385
01386 return qfalse;
01387 }
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397 static void CG_SetDeferredClientInfo( clientInfo_t *ci ) {
01398 int i;
01399 clientInfo_t *match;
01400
01401
01402
01403 for ( i = 0 ; i < cgs.maxclients ; i++ ) {
01404 match = &cgs.clientinfo[ i ];
01405 if ( !match->infoValid || match->deferred ) {
01406 continue;
01407 }
01408 if ( Q_stricmp( ci->skinName, match->skinName ) ||
01409 Q_stricmp( ci->modelName, match->modelName ) ||
01410
01411
01412 (cgs.gametype >= GT_TEAM && ci->team != match->team && ci->team != TEAM_SPECTATOR) ) {
01413 continue;
01414 }
01415
01416
01417
01418
01419
01420
01421
01422
01423
01424
01425 CG_LoadClientInfo( ci );
01426 return;
01427 }
01428
01429
01430 if ( cgs.gametype >= GT_TEAM ) {
01431 for ( i = 0 ; i < cgs.maxclients ; i++ ) {
01432 match = &cgs.clientinfo[ i ];
01433 if ( !match->infoValid || match->deferred ) {
01434 continue;
01435 }
01436 if ( ci->