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->team != TEAM_SPECTATOR &&
01437 (Q_stricmp( ci->skinName, match->skinName ) ||
01438 (cgs.gametype >= GT_TEAM && ci->team != match->team)) ) {
01439 continue;
01440 }
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450 ci->deferred = qtrue;
01451 CG_CopyClientInfoModel( match, ci );
01452 return;
01453 }
01454
01455
01456
01457
01458 CG_LoadClientInfo( ci );
01459 return;
01460 }
01461
01462
01463 for ( i = 0 ; i < cgs.maxclients ; i++ ) {
01464 match = &cgs.clientinfo[ i ];
01465 if ( !match->infoValid ) {
01466 continue;
01467 }
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477 if (match->deferred)
01478 {
01479 continue;
01480 }
01481
01482 ci->deferred = qtrue;
01483 CG_CopyClientInfoModel( match, ci );
01484 return;
01485 }
01486
01487
01488
01489
01490
01491 CG_LoadClientInfo( ci );
01492 }
01493
01494
01495
01496
01497
01498
01499 #include "../namespace_begin.h"
01500 void WP_SetSaber( int entNum, saberInfo_t *sabers, int saberNum, const char *saberName );
01501 #include "../namespace_end.h"
01502
01503 void CG_NewClientInfo( int clientNum, qboolean entitiesInitialized ) {
01504 clientInfo_t *ci;
01505 clientInfo_t newInfo;
01506 const char *configstring;
01507 const char *v;
01508 char *slash;
01509 void *oldGhoul2;
01510 void *oldG2Weapons[MAX_SABERS];
01511 int i = 0;
01512 int k = 0;
01513 qboolean saberUpdate[MAX_SABERS];
01514
01515 ci = &cgs.clientinfo[clientNum];
01516
01517 oldGhoul2 = ci->ghoul2Model;
01518
01519 while (k < MAX_SABERS)
01520 {
01521 oldG2Weapons[k] = ci->ghoul2Weapons[k];
01522 k++;
01523 }
01524
01525 configstring = CG_ConfigString( clientNum + CS_PLAYERS );
01526 if ( !configstring[0] ) {
01527 if (ci->ghoul2Model && trap_G2_HaveWeGhoul2Models(ci->ghoul2Model))
01528 {
01529 trap_G2API_CleanGhoul2Models(&ci->ghoul2Model);
01530 }
01531 k = 0;
01532 while (k < MAX_SABERS)
01533 {
01534 if (ci->ghoul2Weapons[k] && trap_G2_HaveWeGhoul2Models(ci->ghoul2Weapons[k]))
01535 {
01536 trap_G2API_CleanGhoul2Models(&ci->ghoul2Weapons[k]);
01537 }
01538 k++;
01539 }
01540
01541 memset( ci, 0, sizeof( *ci ) );
01542 return;
01543 }
01544
01545
01546
01547 memset( &newInfo, 0, sizeof( newInfo ) );
01548
01549
01550 v = Info_ValueForKey(configstring, "n");
01551 Q_strncpyz( newInfo.name, v, sizeof( newInfo.name ) );
01552
01553
01554 v = Info_ValueForKey( configstring, "c1" );
01555 CG_ColorFromString( v, newInfo.color1 );
01556
01557 newInfo.icolor1 = atoi(v);
01558
01559 v = Info_ValueForKey( configstring, "c2" );
01560 CG_ColorFromString( v, newInfo.color2 );
01561
01562 newInfo.icolor2 = atoi(v);
01563
01564
01565 v = Info_ValueForKey( configstring, "skill" );
01566 newInfo.botSkill = atoi( v );
01567
01568
01569 v = Info_ValueForKey( configstring, "hc" );
01570 newInfo.handicap = atoi( v );
01571
01572
01573 v = Info_ValueForKey( configstring, "w" );
01574 newInfo.wins = atoi( v );
01575
01576
01577 v = Info_ValueForKey( configstring, "l" );
01578 newInfo.losses = atoi( v );
01579
01580
01581 v = Info_ValueForKey( configstring, "t" );
01582 newInfo.team = atoi( v );
01583
01584
01585 if ( clientNum == cg.clientNum)
01586 {
01587 trap_Cvar_Set("ui_team", v);
01588 }
01589
01590
01591 v = Info_ValueForKey( configstring, "tt" );
01592 newInfo.teamTask = atoi(v);
01593
01594
01595 v = Info_ValueForKey( configstring, "tl" );
01596 newInfo.teamLeader = atoi(v);
01597
01598
01599
01600
01601
01602
01603
01604
01605 v = Info_ValueForKey( configstring, "model" );
01606 if ( cg_forceModel.integer ) {
01607
01608
01609 char modelStr[MAX_QPATH];
01610 char *skin;
01611
01612 trap_Cvar_VariableStringBuffer( "model", modelStr, sizeof( modelStr ) );
01613 if ( ( skin = strchr( modelStr, '/' ) ) == NULL) {
01614 skin = "default";
01615 } else {
01616 *skin++ = 0;
01617 }
01618 Q_strncpyz( newInfo.skinName, skin, sizeof( newInfo.skinName ) );
01619 Q_strncpyz( newInfo.modelName, modelStr, sizeof( newInfo.modelName ) );
01620
01621 if ( cgs.gametype >= GT_TEAM ) {
01622
01623 slash = strchr( v, '/' );
01624 if ( slash ) {
01625 Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );
01626 }
01627 }
01628 } else {
01629 Q_strncpyz( newInfo.modelName, v, sizeof( newInfo.modelName ) );
01630
01631 slash = strchr( newInfo.modelName, '/' );
01632 if ( !slash ) {
01633
01634 Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) );
01635 } else {
01636 Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );
01637
01638 *slash = 0;
01639 }
01640 }
01641
01642 if (cgs.gametype == GT_SIEGE)
01643 {
01644
01645 v = Info_ValueForKey( configstring, "sdt" );
01646 if (v && v[0])
01647 {
01648 newInfo.siegeDesiredTeam = atoi(v);
01649 }
01650 else
01651 {
01652 newInfo.siegeDesiredTeam = 0;
01653 }
01654
01655
01656 v = Info_ValueForKey( configstring, "siegeclass" );
01657 newInfo.siegeIndex = -1;
01658
01659 if (v)
01660 {
01661 siegeClass_t *siegeClass = BG_SiegeFindClassByName(v);
01662
01663 if (siegeClass)
01664 {
01665 newInfo.siegeIndex = BG_SiegeFindClassIndexByName(v);
01666
01667 if (siegeClass->forcedModel[0])
01668 {
01669 Q_strncpyz( newInfo.modelName, siegeClass->forcedModel, sizeof( newInfo.modelName ) );
01670 }
01671
01672 if (siegeClass->forcedSkin[0])
01673 {
01674 Q_strncpyz( newInfo.skinName, siegeClass->forcedSkin, sizeof( newInfo.skinName ) );
01675 }
01676
01677 if (siegeClass->hasForcedSaberColor)
01678 {
01679 newInfo.icolor1 = siegeClass->forcedSaberColor;
01680
01681 CG_ColorFromInt( newInfo.icolor1, newInfo.color1 );
01682 }
01683 if (siegeClass->hasForcedSaber2Color)
01684 {
01685 newInfo.icolor2 = siegeClass->forcedSaber2Color;
01686
01687 CG_ColorFromInt( newInfo.icolor2, newInfo.color2 );
01688 }
01689 }
01690 }
01691 }
01692
01693 saberUpdate[0] = qfalse;
01694 saberUpdate[1] = qfalse;
01695
01696
01697 v = Info_ValueForKey( configstring, "st" );
01698
01699 if (v && Q_stricmp(v, ci->saberName))
01700 {
01701 Q_strncpyz( newInfo.saberName, v, 64 );
01702 WP_SetSaber(clientNum, newInfo.saber, 0, newInfo.saberName);
01703 saberUpdate[0] = qtrue;
01704 }
01705 else
01706 {
01707 Q_strncpyz( newInfo.saberName, ci->saberName, 64 );
01708 memcpy(&newInfo.saber[0], &ci->saber[0], sizeof(newInfo.saber[0]));
01709 newInfo.ghoul2Weapons[0] = ci->ghoul2Weapons[0];
01710 }
01711
01712 v = Info_ValueForKey( configstring, "st2" );
01713
01714 if (v && Q_stricmp(v, ci->saber2Name))
01715 {
01716 Q_strncpyz( newInfo.saber2Name, v, 64 );
01717 WP_SetSaber(clientNum, newInfo.saber, 1, newInfo.saber2Name);
01718 saberUpdate[1] = qtrue;
01719 }
01720 else
01721 {
01722 Q_strncpyz( newInfo.saber2Name, ci->saber2Name, 64 );
01723 memcpy(&newInfo.saber[1], &ci->saber[1], sizeof(newInfo.saber[1]));
01724 newInfo.ghoul2Weapons[1] = ci->ghoul2Weapons[1];
01725 }
01726
01727 if (saberUpdate[0] || saberUpdate[1])
01728 {
01729 int j = 0;
01730
01731 while (j < MAX_SABERS)
01732 {
01733 if (saberUpdate[j])
01734 {
01735 if (newInfo.saber[j].model[0])
01736 {
01737 if (oldG2Weapons[j])
01738 {
01739 trap_G2API_CleanGhoul2Models(&oldG2Weapons[j]);
01740 oldG2Weapons[j] = 0;
01741 }
01742
01743 CG_InitG2SaberData(j, &newInfo);
01744 }
01745 else
01746 {
01747 if (oldG2Weapons[j])
01748 {
01749 trap_G2API_CleanGhoul2Models(&oldG2Weapons[j]);
01750 oldG2Weapons[j] = 0;
01751 }
01752 }
01753
01754 cg_entities[clientNum].weapon = 0;
01755 cg_entities[clientNum].ghoul2weapon = NULL;
01756 }
01757 j++;
01758 }
01759 }
01760
01761
01762 k = 0;
01763 while (k < MAX_SABERS)
01764 {
01765 if (oldG2Weapons[k])
01766 {
01767 newInfo.ghoul2Weapons[k] = oldG2Weapons[k];
01768 }
01769 k++;
01770 }
01771
01772
01773 v = Info_ValueForKey( configstring, "dt" );
01774
01775 if (v)
01776 {
01777 newInfo.duelTeam = atoi(v);
01778 }
01779 else
01780 {
01781 newInfo.duelTeam = 0;
01782 }
01783
01784
01785 v = Info_ValueForKey( configstring, "forcepowers" );
01786 Q_strncpyz( newInfo.forcePowers, v, sizeof( newInfo.forcePowers ) );
01787
01788 if (cgs.gametype >= GT_TEAM && !cgs.jediVmerc && cgs.gametype != GT_SIEGE )
01789 {
01790 BG_ValidateSkinForTeam( newInfo.modelName, newInfo.skinName, newInfo.team, newInfo.colorOverride );
01791 }
01792 else
01793 {
01794 newInfo.colorOverride[0] = newInfo.colorOverride[1] = newInfo.colorOverride[2] = 0.0f;
01795 }
01796
01797
01798
01799 if ( !CG_ScanForExistingClientInfo( &newInfo, clientNum ) ) {
01800
01801 if (cg.snap && cg.snap->ps.clientNum == clientNum)
01802 {
01803 CG_LoadClientInfo( &newInfo );
01804 }
01805 else if ( cg_deferPlayers.integer && cgs.gametype != GT_SIEGE && !cg_buildScript.integer && !cg.loading ) {
01806
01807 CG_SetDeferredClientInfo( &newInfo );
01808 } else {
01809 CG_LoadClientInfo( &newInfo );
01810 }
01811 }
01812
01813
01814 newInfo.infoValid = qtrue;
01815 if (ci->ghoul2Model &&
01816 ci->ghoul2Model != newInfo.ghoul2Model &&
01817 trap_G2_HaveWeGhoul2Models(ci->ghoul2Model))
01818 {
01819
01820 trap_G2API_CleanGhoul2Models(&ci->ghoul2Model);
01821 }
01822 *ci = newInfo;
01823
01824
01825 while (i < MAX_CLIENTS)
01826 {
01827 cg_entities[i].ghoul2weapon = NULL;
01828 i++;
01829 }
01830
01831 if (clientNum != -1)
01832 {
01833 trap_G2API_ClearAttachedInstance(clientNum);
01834 }
01835
01836
01837 if (entitiesInitialized && ci->ghoul2Model && (oldGhoul2 != ci->ghoul2Model))
01838 {
01839 animation_t *anim;
01840 centity_t *cent = &cg_entities[clientNum];
01841
01842 anim = &bgHumanoidAnimations[ (cg_entities[clientNum].currentState.legsAnim) ];
01843
01844 if (anim)
01845 {
01846 int flags = BONE_ANIM_OVERRIDE_FREEZE;
01847 int firstFrame = anim->firstFrame;
01848 int setFrame = -1;
01849 float animSpeed = 50.0f / anim->frameLerp;
01850
01851 if (anim->loopFrames != -1)
01852 {
01853 flags = BONE_ANIM_OVERRIDE_LOOP;
01854 }
01855
01856 if (cent->pe.legs.frame >= anim->firstFrame && cent->pe.legs.frame <= (anim->firstFrame + anim->numFrames))
01857 {
01858 setFrame = cent->pe.legs.frame;
01859 }
01860
01861
01862 trap_G2API_SetBoneAnim(ci->ghoul2Model, 0, "model_root", firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, setFrame, 150);
01863
01864 cg_entities[clientNum].currentState.legsAnim = 0;
01865 }
01866
01867 anim = &bgHumanoidAnimations[ (cg_entities[clientNum].currentState.torsoAnim) ];
01868
01869 if (anim)
01870 {
01871 int flags = BONE_ANIM_OVERRIDE_FREEZE;
01872 int firstFrame = anim->firstFrame;
01873 int setFrame = -1;
01874 float animSpeed = 50.0f / anim->frameLerp;
01875
01876 if (anim->loopFrames != -1)
01877 {
01878 flags = BONE_ANIM_OVERRIDE_LOOP;
01879 }
01880
01881 if (cent->pe.torso.frame >= anim->firstFrame && cent->pe.torso.frame <= (anim->firstFrame + anim->numFrames))
01882 {
01883 setFrame = cent->pe.torso.frame;
01884 }
01885
01886
01887 trap_G2API_SetBoneAnim(ci->ghoul2Model, 0, "lower_lumbar", firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, setFrame, 150);
01888
01889 cg_entities[clientNum].currentState.torsoAnim = 0;
01890 }
01891
01892 if (cg_entities[clientNum].ghoul2 && trap_G2_HaveWeGhoul2Models(cg_entities[clientNum].ghoul2))
01893 {
01894 trap_G2API_CleanGhoul2Models(&cg_entities[clientNum].ghoul2);
01895 }
01896 trap_G2API_DuplicateGhoul2Instance(ci->ghoul2Model, &cg_entities[clientNum].ghoul2);
01897
01898 if (clientNum != -1)
01899 {
01900
01901
01902 trap_G2API_AttachInstanceToEntNum(cg_entities[clientNum].ghoul2, clientNum, qfalse);
01903 }
01904
01905 if (trap_G2API_AddBolt(cg_entities[clientNum].ghoul2, 0, "face") == -1)
01906 {
01907 cg_entities[clientNum].noFace = qtrue;
01908 }
01909
01910 cg_entities[clientNum].localAnimIndex = CG_G2SkelForModel(cg_entities[clientNum].ghoul2);
01911 cg_entities[clientNum].eventAnimIndex = CG_G2EvIndexForModel(cg_entities[clientNum].ghoul2, cg_entities[clientNum].localAnimIndex);
01912
01913 if (cg_entities[clientNum].currentState.number != cg.predictedPlayerState.clientNum &&
01914 cg_entities[clientNum].currentState.weapon == WP_SABER)
01915 {
01916 cg_entities[clientNum].weapon = cg_entities[clientNum].currentState.weapon;
01917 if (cg_entities[clientNum].ghoul2 && ci->ghoul2Model)
01918 {
01919 CG_CopyG2WeaponInstance(&cg_entities[clientNum], cg_entities[clientNum].currentState.weapon, cg_entities[clientNum].ghoul2);
01920 cg_entities[clientNum].ghoul2weapon = CG_G2WeaponInstance(&cg_entities[clientNum], cg_entities[clientNum].currentState.weapon);
01921 }
01922 if (!cg_entities[clientNum].currentState.saberHolstered)
01923 {
01924 int j;
01925 BG_SI_SetDesiredLength(&ci->saber[0], 0, -1);
01926 BG_SI_SetDesiredLength(&ci->saber[1], 0, -1);
01927
01928 i = 0;
01929 while (i < MAX_SABERS)
01930 {
01931 j = 0;
01932 while (j < ci->saber[i].numBlades)
01933 {
01934 ci->saber[i].blade[j].length = ci->saber[i].blade[j].lengthMax;
01935 j++;
01936 }
01937 i++;
01938 }
01939 }
01940 }
01941 }
01942 }
01943
01944
01945 qboolean cgQueueLoad = qfalse;
01946
01947
01948
01949
01950
01951
01952
01953 void CG_ActualLoadDeferredPlayers( void )
01954 {
01955 int i;
01956 clientInfo_t *ci;
01957
01958
01959 for ( i = 0, ci = cgs.clientinfo ; i < cgs.maxclients ; i++, ci++ ) {
01960 if ( ci->infoValid && ci->deferred ) {
01961 CG_LoadClientInfo( ci );
01962
01963 }
01964 }
01965 }
01966
01967
01968
01969
01970
01971
01972
01973
01974
01975
01976 void CG_LoadDeferredPlayers( void ) {
01977 cgQueueLoad = qtrue;
01978 }
01979
01980
01981
01982
01983
01984
01985
01986
01987
01988 #define FOOTSTEP_DISTANCE 32
01989 static void _PlayerFootStep( const vec3_t origin,
01990 const float orientation,
01991 const float radius,
01992 centity_t *const cent, footstepType_t footStepType )
01993 {
01994 vec3_t end, mins = {-7, -7, 0}, maxs = {7, 7, 2};
01995 trace_t trace;
01996 footstep_t soundType = FOOTSTEP_TOTAL;
01997 qboolean bMark = qfalse;
01998 qhandle_t footMarkShader;
01999 int effectID = -1;
02000
02001
02002
02003 VectorCopy( origin, end );
02004 end[2] -= FOOTSTEP_DISTANCE;
02005
02006 trap_CM_BoxTrace( &trace, origin, end, mins, maxs, 0, MASK_PLAYERSOLID );
02007
02008
02009 if ( trace.fraction >= 1.0f )
02010 {
02011 return;
02012 }
02013
02014
02015 switch( trace.surfaceFlags & MATERIAL_MASK )
02016 {
02017 case MATERIAL_MUD:
02018 bMark = qtrue;
02019 if ( footStepType == FOOTSTEP_HEAVY_R || footStepType == FOOTSTEP_HEAVY_L) {
02020 soundType = FOOTSTEP_MUDRUN;
02021 } else {
02022 soundType = FOOTSTEP_MUDWALK;
02023 }
02024 effectID = cgs.effects.footstepMud;
02025 break;
02026 case MATERIAL_DIRT:
02027 bMark = qtrue;
02028 if ( footStepType == FOOTSTEP_HEAVY_R || footStepType == FOOTSTEP_HEAVY_L) {
02029 soundType = FOOTSTEP_DIRTRUN;
02030 } else {
02031 soundType = FOOTSTEP_DIRTWALK;
02032 }
02033 effectID = cgs.effects.footstepSand;
02034 break;
02035 case MATERIAL_SAND:
02036 bMark = qtrue;
02037 if ( footStepType == FOOTSTEP_HEAVY_R || footStepType == FOOTSTEP_HEAVY_L) {
02038 soundType = FOOTSTEP_SANDRUN;
02039 } else {
02040 soundType = FOOTSTEP_SANDWALK;
02041 }
02042 effectID = cgs.effects.footstepSand;
02043 break;
02044 case MATERIAL_SNOW:
02045 bMark = qtrue;
02046 if ( footStepType == FOOTSTEP_HEAVY_R || footStepType == FOOTSTEP_HEAVY_L) {
02047 soundType = FOOTSTEP_SNOWRUN;
02048 } else {
02049 soundType = FOOTSTEP_SNOWWALK;
02050 }
02051 effectID = cgs.effects.footstepSnow;
02052 break;
02053 case MATERIAL_SHORTGRASS:
02054 case MATERIAL_LONGGRASS:
02055 if ( footStepType == FOOTSTEP_HEAVY_R || footStepType == FOOTSTEP_HEAVY_L) {
02056 soundType = FOOTSTEP_GRASSRUN;
02057 } else {
02058 soundType = FOOTSTEP_GRASSWALK;
02059 }
02060 break;
02061 case MATERIAL_SOLIDMETAL:
02062 if ( footStepType == FOOTSTEP_HEAVY_R || footStepType == FOOTSTEP_HEAVY_L) {
02063 soundType = FOOTSTEP_METALRUN;
02064 } else {
02065 soundType = FOOTSTEP_METALWALK;
02066 }
02067 break;
02068 case MATERIAL_HOLLOWMETAL:
02069 if ( footStepType == FOOTSTEP_HEAVY_R || footStepType == FOOTSTEP_HEAVY_L) {
02070 soundType = FOOTSTEP_PIPERUN;
02071 } else {
02072 soundType = FOOTSTEP_PIPEWALK;
02073 }
02074 break;
02075 case MATERIAL_GRAVEL:
02076 if ( footStepType == FOOTSTEP_HEAVY_R || footStepType == FOOTSTEP_HEAVY_L) {
02077 soundType = FOOTSTEP_GRAVELRUN;
02078 } else {
02079 soundType = FOOTSTEP_GRAVELWALK;
02080 }
02081 effectID = cgs.effects.footstepGravel;
02082 break;
02083 case MATERIAL_CARPET:
02084 case MATERIAL_FABRIC:
02085 case MATERIAL_CANVAS:
02086 case MATERIAL_RUBBER:
02087 case MATERIAL_PLASTIC:
02088 if ( footStepType == FOOTSTEP_HEAVY_R || footStepType == FOOTSTEP_HEAVY_L) {
02089 soundType = FOOTSTEP_RUGRUN;
02090 } else {
02091 soundType = FOOTSTEP_RUGWALK;
02092 }
02093 break;
02094 case MATERIAL_SOLIDWOOD:
02095 case MATERIAL_HOLLOWWOOD:
02096 if ( footStepType == FOOTSTEP_HEAVY_R || footStepType == FOOTSTEP_HEAVY_L) {
02097 soundType = FOOTSTEP_WOODRUN;
02098 } else {
02099 soundType = FOOTSTEP_WOODWALK;
02100 }
02101 break;
02102
02103 default:
02104
02105 case MATERIAL_GLASS:
02106 case MATERIAL_WATER:
02107 case MATERIAL_FLESH:
02108 case MATERIAL_BPGLASS:
02109 case MATERIAL_DRYLEAVES:
02110 case MATERIAL_GREENLEAVES:
02111 case MATERIAL_TILES:
02112 case MATERIAL_PLASTER:
02113 case MATERIAL_SHATTERGLASS:
02114 case MATERIAL_ARMOR:
02115 case MATERIAL_COMPUTER:
02116
02117 case MATERIAL_CONCRETE:
02118 case MATERIAL_ROCK:
02119 case MATERIAL_ICE:
02120 case MATERIAL_MARBLE:
02121 if ( footStepType == FOOTSTEP_HEAVY_R || footStepType == FOOTSTEP_HEAVY_L) {
02122 soundType = FOOTSTEP_STONERUN;
02123 } else {
02124 soundType = FOOTSTEP_STONEWALK;
02125 }
02126 break;
02127 }
02128 if (soundType < FOOTSTEP_TOTAL)
02129 {
02130 trap_S_StartSound( NULL, cent->currentState.clientNum, CHAN_BODY, cgs.media.footsteps[soundType][rand()&3] );
02131 }
02132
02133 if ( cg_footsteps.integer < 4 )
02134 {
02135 if ( cg_footsteps.integer < 2 )
02136 {
02137 return;
02138 }
02139 }
02140
02141 if ( effectID != -1 )
02142 {
02143 trap_FX_PlayEffectID( effectID, trace.endpos, trace.plane.normal, -1, -1 );
02144 }
02145
02146 if ( cg_footsteps.integer < 4 )
02147 {
02148 if ( !bMark || cg_footsteps.integer < 3 )
02149 {
02150 return;
02151 }
02152 }
02153
02154 switch ( footStepType )
02155 {
02156 case FOOTSTEP_HEAVY_R:
02157 footMarkShader = cgs.media.fshrMarkShader;
02158 break;
02159 case FOOTSTEP_HEAVY_L:
02160 footMarkShader = cgs.media.fshlMarkShader;
02161 break;
02162 case FOOTSTEP_R:
02163 footMarkShader = cgs.media.fsrMarkShader;
02164 break;
02165 default:
02166 case FOOTSTEP_L:
02167 footMarkShader = cgs.media.fslMarkShader;
02168 break;
02169 }
02170
02171
02172
02173
02174
02175
02176 if (trace.plane.normal[0] || trace.plane.normal[1] || trace.plane.normal[2])
02177 {
02178 CG_ImpactMark( footMarkShader, trace.endpos, trace.plane.normal,
02179 orientation, 1,1,1, 1.0f, qfalse, radius, qfalse );
02180 }
02181 }
02182
02183 static void CG_PlayerFootsteps( centity_t *cent, footstepType_t footStepType )
02184 {
02185 if ( !cg_footsteps.integer )
02186 {
02187 return;
02188 }
02189
02190
02191 if ( cent->currentState.NPC_class != CLASS_ATST
02192 && cent->currentState.NPC_class != CLASS_CLAW
02193 && cent->currentState.NPC_class != CLASS_FISH
02194 && cent->currentState.NPC_class != CLASS_FLIER2
02195 && cent->currentState.NPC_class != CLASS_GLIDER
02196 && cent->currentState.NPC_class != CLASS_INTERROGATOR
02197 && cent->currentState.NPC_class != CLASS_MURJJ
02198 && cent->currentState.NPC_class != CLASS_PROBE
02199 && cent->currentState.NPC_class != CLASS_R2D2
02200 && cent->currentState.NPC_class != CLASS_R5D2
02201 && cent->currentState.NPC_class != CLASS_REMOTE
02202 && cent->currentState.NPC_class != CLASS_SEEKER
02203 && cent->currentState.NPC_class != CLASS_SENTRY
02204 && cent->currentState.NPC_class != CLASS_SWAMP )
02205 {
02206 mdxaBone_t boltMatrix;
02207 vec3_t tempAngles, sideOrigin;
02208 int footBolt = -1;
02209
02210 tempAngles[PITCH] = 0;
02211 tempAngles[YAW] = cent->pe.legs.yawAngle;
02212 tempAngles[ROLL] = 0;
02213
02214 switch ( footStepType )
02215 {
02216 case FOOTSTEP_R:
02217 case FOOTSTEP_HEAVY_R:
02218 footBolt = trap_G2API_AddBolt(cent->ghoul2, 0, "*r_leg_foot");
02219 break;
02220 case FOOTSTEP_L:
02221 case FOOTSTEP_HEAVY_L:
02222 default:
02223 footBolt = trap_G2API_AddBolt(cent->ghoul2, 0, "*l_leg_foot");
02224 break;
02225 }
02226
02227
02228
02229 trap_G2API_GetBoltMatrix( cent->ghoul2, 0, footBolt, &boltMatrix, tempAngles, cent->lerpOrigin,
02230 cg.time, cgs.gameModels, cent->modelScale);
02231 BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, sideOrigin );
02232 sideOrigin[2] += 15;
02233 _PlayerFootStep( sideOrigin, cent->pe.legs.yawAngle, 6, cent, footStepType );
02234 }
02235 }
02236
02237 void CG_PlayerAnimEventDo( centity_t *cent, animevent_t *animEvent )
02238 {
02239 soundChannel_t channel = CHAN_AUTO;
02240 clientInfo_t *client = NULL;
02241 qhandle_t swingSound = 0;
02242 qhandle_t spinSound = 0;
02243
02244 if ( !cent || !animEvent )
02245 {
02246 return;
02247 }
02248
02249 switch ( animEvent->eventType )
02250 {
02251 case AEV_SOUNDCHAN:
02252 channel = (soundChannel_t)animEvent->eventData[AED_SOUNDCHANNEL];
02253 case AEV_SOUND:
02254 {
02255 const int holdSnd = animEvent->eventData[ AED_SOUNDINDEX_START+Q_irand( 0, animEvent->eventData[AED_SOUND_NUMRANDOMSNDS] ) ];
02256 if ( holdSnd > 0 )
02257 {
02258 trap_S_StartSound( NULL, cent->currentState.number, channel, holdSnd );
02259 }
02260 }
02261 break;
02262 case AEV_SABER_SWING:
02263 if (cent->currentState.eType == ET_NPC)
02264 {
02265 client = cent->npcClient;
02266 assert(client);
02267 }
02268 else
02269 {
02270 client = &cgs.clientinfo[cent->currentState.clientNum];
02271 }
02272 if ( client && client->infoValid && client->saber[animEvent->eventData[AED_SABER_SWING_SABERNUM]].swingSound[0] )
02273 {
02274 swingSound = client->saber[0].swingSound[Q_irand(0,2)];
02275 }
02276 else
02277 {
02278 int randomSwing = 1;
02279 switch ( animEvent->eventData[AED_SABER_SWING_TYPE] )
02280 {
02281 default:
02282 case 0:
02283 randomSwing = Q_irand( 1, 3 );
02284 break;
02285 case 1:
02286 randomSwing = Q_irand( 4, 6 );
02287 break;
02288 case 2:
02289 randomSwing = Q_irand( 7, 9 );
02290 break;
02291 }
02292 swingSound = trap_S_RegisterSound(va("sound/weapons/saber/saberhup%i.wav", randomSwing));
02293 }
02294 trap_S_StartSound(cent->currentState.pos.trBase, cent->currentState.number, CHAN_AUTO, swingSound );
02295 break;
02296 case AEV_SABER_SPIN:
02297 if (cent->currentState.eType == ET_NPC)
02298 {
02299 client = cent->npcClient;
02300 assert(client);
02301 }
02302 else
02303 {
02304 client = &cgs.clientinfo[cent->currentState.clientNum];
02305 }
02306 if ( client
02307 && client->infoValid
02308 && client->saber[AED_SABER_SPIN_SABERNUM].spinSound )
02309 {
02310 spinSound = client->saber[AED_SABER_SPIN_SABERNUM].spinSound;
02311 }
02312 else
02313 {
02314 switch ( animEvent->eventData[AED_SABER_SPIN_TYPE] )
02315 {
02316 case 0:
02317 spinSound = trap_S_RegisterSound( "sound/weapons/saber/saberspinoff.wav" );
02318 break;
02319 case 1:
02320 spinSound = trap_S_RegisterSound( "sound/weapons/saber/saberspin.wav" );
02321 break;
02322 case 2:
02323 spinSound = trap_S_RegisterSound( "sound/weapons/saber/saberspin1.wav" );
02324 break;
02325 case 3:
02326 spinSound = trap_S_RegisterSound( "sound/weapons/saber/saberspin2.wav" );
02327 break;
02328 case 4:
02329 spinSound = trap_S_RegisterSound( "sound/weapons/saber/saberspin3.wav" );
02330 break;
02331 default:
02332 spinSound = trap_S_RegisterSound( va( "sound/weapons/saber/saberspin%d.wav", Q_irand(1,3)) );
02333 break;
02334 }
02335 }
02336 if ( spinSound )
02337 {
02338 trap_S_StartSound( NULL, cent->currentState.clientNum, CHAN_AUTO, spinSound );
02339 }
02340 break;
02341 case AEV_FOOTSTEP:
02342 CG_PlayerFootsteps( cent, (footstepType_t)animEvent->eventData[AED_FOOTSTEP_TYPE] );
02343 break;
02344 case AEV_EFFECT:
02345 #if 0 //SP method
02346
02347 if ( animEvent->stringData != NULL && cent && cent->gent && cent->gent->ghoul2.size() )
02348 {
02349 animEvent->eventData[AED_BOLTINDEX] = gi.G2API_AddBolt( ¢->gent->ghoul2[cent->gent->playerModel], animEvent->stringData );
02350 animEvent->stringData = NULL;
02351 }
02352 if ( animEvent->eventData[AED_BOLTINDEX] != -1 )
02353 {
02354 G_PlayEffect( animEvent->eventData[AED_EFFECTINDEX], cent->gent->playerModel, animEvent->eventData[AED_BOLTINDEX], cent->currentState.clientNum );
02355 }
02356 else
02357 {
02358 theFxScheduler.PlayEffect( animEvent->eventData[AED_EFFECTINDEX], cent->lerpOrigin, qfalse );
02359 }
02360 #else //my method
02361 if (animEvent->stringData && animEvent->stringData[0] && cent && cent->ghoul2)
02362 {
02363 animEvent->eventData[AED_MODELINDEX] = 0;
02364 if ( ( Q_stricmpn( "*blade", animEvent->stringData, 6 ) == 0
02365 || Q_stricmp( "*flash", animEvent->stringData ) == 0 ) )
02366 {
02367 animEvent->eventData[AED_BOLTINDEX] = trap_G2API_AddBolt( cent->ghoul2, 1, animEvent->stringData );
02368 if ( animEvent->eventData[AED_BOLTINDEX] != -1 )
02369 {
02370 animEvent->eventData[AED_MODELINDEX] = 1;
02371 }
02372 else
02373 {
02374 animEvent->eventData[AED_BOLTINDEX] = trap_G2API_AddBolt( cent->ghoul2, 0, animEvent->stringData );
02375 }
02376 }
02377 else
02378 {
02379 animEvent->eventData[AED_BOLTINDEX] = trap_G2API_AddBolt( cent->ghoul2, 0, animEvent->stringData );
02380 }
02381 animEvent->stringData[0] = 0;
02382 }
02383 if ( animEvent->eventData[AED_BOLTINDEX] != -1 )
02384 {
02385 vec3_t lAngles;
02386 vec3_t bPoint, bAngle;
02387 mdxaBone_t matrix;
02388
02389 VectorSet(lAngles, 0, cent->lerpAngles[YAW], 0);
02390
02391 trap_G2API_GetBoltMatrix(cent->ghoul2, animEvent->eventData[AED_MODELINDEX], animEvent->eventData[AED_BOLTINDEX], &matrix, lAngles,
02392 cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale);
02393 BG_GiveMeVectorFromMatrix(&matrix, ORIGIN, bPoint);
02394 VectorSet(bAngle, 0, 1, 0);
02395
02396 trap_FX_PlayEffectID(animEvent->eventData[AED_EFFECTINDEX], bPoint, bAngle, -1, -1);
02397 }
02398 else
02399 {
02400 vec3_t bAngle;
02401
02402 VectorSet(bAngle, 0, 1, 0);
02403 trap_FX_PlayEffectID(animEvent->eventData[AED_EFFECTINDEX], cent->lerpOrigin, bAngle, -1, -1);
02404 }
02405 #endif
02406 break;
02407
02408 case AEV_FIRE:
02409 case AEV_MOVE:
02410 break;
02411
02412
02413
02414
02415
02416
02417
02418
02419
02420
02421
02422
02423
02424
02425
02426
02427
02428
02429
02430
02431
02432
02433
02434
02435
02436
02437
02438
02439
02440
02441
02442
02443
02444
02445
02446
02447
02448
02449 default:
02450 return;
02451 break;
02452 }
02453 }
02454
02455
02456
02457
02458
02459
02460
02461 void CG_PlayerAnimEvents( int animFileIndex, int eventFileIndex, qboolean torso, int oldFrame, int frame, int entNum )
02462 {
02463 int i;
02464 int firstFrame = 0, lastFrame = 0;
02465 qboolean doEvent = qfalse, inSameAnim = qfalse, loopAnim = qfalse, match = qfalse, animBackward = qfalse;
02466 animevent_t *animEvents = NULL;
02467
02468 if ( torso )
02469 {
02470 animEvents = bgAllEvents[eventFileIndex].torsoAnimEvents;
02471 }
02472 else
02473 {
02474 animEvents = bgAllEvents[eventFileIndex].legsAnimEvents;
02475 }
02476 if ( fabs((float)(oldFrame-frame)) > 1 )
02477 {
02478 int oldAnim, anim;
02479 if ( torso )
02480 {
02481
02482
02483
02484
02485
02486
02487
02488
02489 {
02490 oldAnim = cg_entities[entNum].currentState.torsoAnim;
02491 anim = cg_entities[entNum].nextState.torsoAnim;
02492 }
02493 }
02494 else
02495 {
02496
02497
02498
02499
02500
02501
02502
02503
02504 {
02505 oldAnim = cg_entities[entNum].currentState.legsAnim;
02506 anim = cg_entities[entNum].nextState.legsAnim;
02507 }
02508 }
02509 if ( anim != oldAnim )
02510 {
02511 inSameAnim = qfalse;
02512
02513 }
02514 else
02515 {
02516 animation_t *animation;
02517
02518 inSameAnim = qtrue;
02519 animation = &bgAllAnims[animFileIndex].anims[anim];
02520 animBackward = (animation->frameLerp<0);
02521 if ( animation->loopFrames != -1 )
02522 {
02523 loopAnim = qtrue;
02524 firstFrame = animation->firstFrame;
02525 lastFrame = animation->firstFrame+animation->numFrames;
02526 }
02527 }
02528 }
02529
02530
02531 for (i=0;i<MAX_ANIM_EVENTS;++i)
02532 {
02533 if ( animEvents[i].eventType == AEV_NONE )
02534 {
02535 break;
02536 }
02537
02538 match = qfalse;
02539 if ( animEvents[i].keyFrame == frame )
02540 {
02541 match = qtrue;
02542 }
02543 else if ( fabs((float)(oldFrame-frame)) > 1 )
02544 {
02545 if ( inSameAnim )
02546 {
02547 if ( fabs((float)(oldFrame-animEvents[i].keyFrame)) <= 3
02548 || fabs((float)(frame-animEvents[i].keyFrame)) <= 3 )
02549 {
02550 if ( animBackward )
02551 {
02552 if ( oldFrame > animEvents[i].keyFrame && frame < animEvents[i].keyFrame )
02553 {
02554 match = qtrue;
02555 }
02556 else if ( loopAnim )
02557 {
02558 if ( animEvents[i].keyFrame >= firstFrame && animEvents[i].keyFrame < lastFrame )
02559 {
02560 if ( oldFrame > animEvents[i].keyFrame
02561 && frame > oldFrame )
02562 {
02563 match = qtrue;
02564 }
02565 }
02566 }
02567 }
02568 else
02569 {
02570 if ( oldFrame < animEvents[i].keyFrame && frame > animEvents[i].keyFrame )
02571 {
02572 match = qtrue;
02573 }
02574 else if ( loopAnim )
02575 {
02576 if ( animEvents[i].keyFrame >= firstFrame && animEvents[i].keyFrame < lastFrame )
02577 {
02578 if ( oldFrame < animEvents[i].keyFrame
02579 && frame < oldFrame )
02580 {
02581 match = qtrue;
02582 }
02583 }
02584 }
02585 }
02586 }
02587 }
02588 }
02589 if ( match )
02590 {
02591 switch ( animEvents[i].eventType )
02592 {
02593 case AEV_SOUND:
02594 case AEV_SOUNDCHAN:
02595
02596 if (!animEvents[i].eventData[AED_SOUND_PROBABILITY])
02597 {
02598 doEvent = qtrue;
02599 }
02600 else if (animEvents[i].eventData[AED_SOUND_PROBABILITY] > Q_irand(0, 99) )
02601 {
02602 doEvent = qtrue;
02603 }
02604 break;
02605 case AEV_SABER_SWING:
02606
02607 if (!animEvents[i].eventData[AED_SABER_SWING_PROBABILITY])
02608 {
02609 doEvent = qtrue;
02610 }
02611 else if (animEvents[i].eventData[AED_SABER_SWING_PROBABILITY] > Q_irand(0, 99) )
02612 {
02613 doEvent = qtrue;
02614 }
02615 break;
02616 case AEV_SABER_SPIN:
02617
02618 if (!animEvents[i].eventData[AED_SABER_SPIN_PROBABILITY])
02619 {
02620 doEvent = qtrue;
02621 }
02622 else if (animEvents[i].eventData[AED_SABER_SPIN_PROBABILITY] > Q_irand(0, 99) )
02623 {
02624 doEvent = qtrue;
02625 }
02626 break;
02627 case AEV_FOOTSTEP:
02628
02629 if (!animEvents[i].eventData[AED_FOOTSTEP_PROBABILITY])
02630 {
02631 doEvent = qtrue;
02632 }
02633 else if (animEvents[i].eventData[AED_FOOTSTEP_PROBABILITY] > Q_irand(0, 99) )
02634 {
02635 doEvent = qtrue;
02636 }
02637 break;
02638 case AEV_EFFECT:
02639
02640 if (!animEvents[i].eventData[AED_EFFECT_PROBABILITY])
02641 {
02642 doEvent = qtrue;
02643 }
02644 else if (animEvents[i].eventData[AED_EFFECT_PROBABILITY] > Q_irand(0, 99) )
02645 {
02646 doEvent = qtrue;
02647 }
02648 break;
02649 case AEV_FIRE:
02650
02651 if (!animEvents[i].eventData[AED_FIRE_PROBABILITY])
02652 {
02653 doEvent = qtrue;
02654 }
02655 else if (animEvents[i].eventData[AED_FIRE_PROBABILITY] > Q_irand(0, 99) )
02656 {
02657 doEvent = qtrue;
02658 }
02659 break;
02660 case AEV_MOVE:
02661 doEvent = qtrue;
02662 break;
02663 default:
02664
02665 break;
02666 }
02667
02668 if ( doEvent )
02669 {
02670 CG_PlayerAnimEventDo( &cg_entities[entNum], &animEvents[i] );
02671 }
02672 }
02673 }
02674 }
02675
02676 void CG_TriggerAnimSounds( centity_t *cent )
02677 {
02678 int curFrame = 0;
02679 float currentFrame = 0;
02680 int sFileIndex;
02681
02682 assert(cent->localAnimIndex >= 0);
02683
02684 sFileIndex = cent->eventAnimIndex;
02685
02686 if (trap_G2API_GetBoneFrame(cent->ghoul2, "model_root", cg.time, ¤tFrame, cgs.gameModels, 0))
02687 {
02688
02689 curFrame = floor( currentFrame );
02690 }
02691 if ( curFrame != cent->pe.legs.frame )
02692 {
02693 CG_PlayerAnimEvents( cent->localAnimIndex, sFileIndex, qfalse, cent->pe.legs.frame, curFrame, cent->currentState.number );
02694 }
02695 cent->pe.legs.oldFrame = cent->pe.torso.frame;
02696 cent->pe.legs.frame = curFrame;
02697
02698 if (cent->noLumbar)
02699 {
02700 cent->pe.torso.oldFrame = cent->pe.legs.oldFrame;
02701 cent->pe.torso.frame = cent->pe.legs.frame;
02702 return;
02703 }
02704
02705 if (trap_G2API_GetBoneFrame(cent->ghoul2, "lower_lumbar", cg.time, ¤tFrame, cgs.gameModels, 0))
02706 {
02707 curFrame = floor( currentFrame );
02708 }
02709 if ( curFrame != cent->pe.torso.frame )
02710 {
02711 CG_PlayerAnimEvents( cent->localAnimIndex, sFileIndex, qtrue, cent->pe.torso.frame, curFrame, cent->currentState.number );
02712 }
02713 cent->pe.torso.oldFrame = cent->pe.torso.frame;
02714 cent->pe.torso.frame = curFrame;
02715 cent->pe.torso.backlerp = 1.0f - (currentFrame - (float)curFrame);
02716 }
02717
02718
02719 static qboolean CG_FirstAnimFrame(lerpFrame_t *lf, qboolean torsoOnly, float speedScale);
02720
02721 qboolean CG_InRoll( centity_t *cent )
02722 {
02723 switch ( (cent->currentState.legsAnim) )
02724 {
02725 case BOTH_GETUP_BROLL_B:
02726 case BOTH_GETUP_BROLL_F:
02727 case BOTH_GETUP_BROLL_L:
02728 case BOTH_GETUP_BROLL_R:
02729 case BOTH_GETUP_FROLL_B:
02730 case BOTH_GETUP_FROLL_F:
02731 case BOTH_GETUP_FROLL_L:
02732 case BOTH_GETUP_FROLL_R:
02733 case BOTH_ROLL_F:
02734 case BOTH_ROLL_B:
02735 case BOTH_ROLL_R:
02736 case BOTH_ROLL_L:
02737 if ( cent->pe.legs.animationTime > cg.time )
02738 {
02739 return qtrue;
02740 }
02741 break;
02742 }
02743 return qfalse;
02744 }
02745
02746 qboolean CG_InRollAnim( centity_t *cent )
02747 {
02748 switch ( (cent->currentState.legsAnim) )
02749 {
02750 case BOTH_ROLL_F:
02751 case BOTH_ROLL_B:
02752 case BOTH_ROLL_R:
02753 case BOTH_ROLL_L:
02754 return qtrue;
02755 }
02756 return qfalse;
02757 }
02758
02759
02760
02761
02762
02763
02764 #include "../namespace_begin.h"
02765 qboolean BG_SaberStanceAnim( int anim );
02766 qboolean PM_RunningAnim( int anim );
02767 #include "../namespace_end.h"
02768 static void CG_SetLerpFrameAnimation( centity_t *cent, clientInfo_t *ci, lerpFrame_t *lf, int newAnimation, float animSpeedMult, qboolean torsoOnly, qboolean flipState) {
02769 animation_t *anim;
02770 float animSpeed;
02771 int flags=BONE_ANIM_OVERRIDE_FREEZE;
02772 int oldAnim = -1;
02773 int blendTime = 100;
02774 float oldSpeed = lf->animationSpeed;
02775
02776 if (cent->localAnimIndex > 0)
02777 {
02778 ci->brokenLimbs = cent->currentState.brokenLimbs;
02779 }
02780
02781 oldAnim = lf->animationNumber;
02782
02783 lf->animationNumber = newAnimation;
02784
02785 if ( newAnimation < 0 || newAnimation >= MAX_TOTALANIMATIONS ) {
02786 CG_Error( "Bad animation number: %i", newAnimation );
02787 }
02788
02789 anim = &bgAllAnims[cent->localAnimIndex].anims[ newAnimation ];
02790
02791 lf->animation = anim;
02792 lf->animationTime = lf->frameTime + abs(anim->frameLerp);
02793
02794 if (cent->localAnimIndex > 1 &&
02795 anim->firstFrame == 0 &&
02796 anim->numFrames == 0)
02797 {
02798 return;
02799 }
02800
02801 if ( cg_debugAnim.integer && (cg_debugAnim.integer < 0 || cg_debugAnim.integer == cent->currentState.clientNum) ) {
02802 if (lf == ¢->pe.legs)
02803 {
02804 CG_Printf( "%d: %d TORSO Anim: %i, '%s'\n", cg.time, cent->currentState.clientNum, newAnimation, GetStringForID(animTable, newAnimation));
02805 }
02806 else
02807 {
02808 CG_Printf( "%d: %d LEGS Anim: %i, '%s'\n", cg.time, cent->currentState.clientNum, newAnimation, GetStringForID(animTable, newAnimation));
02809 }
02810 }
02811
02812 if (cent->ghoul2)
02813 {
02814 qboolean resumeFrame = qfalse;
02815 int beginFrame = -1;
02816 int firstFrame;
02817 int lastFrame;
02818 #if 0 //disabled for now
02819 float unused;
02820 #endif
02821
02822 animSpeed = 50.0f / anim->frameLerp;
02823 if (lf->animation->loopFrames != -1)
02824 {
02825 flags = BONE_ANIM_OVERRIDE_LOOP;
02826 }
02827
02828 if (animSpeed < 0)
02829 {
02830 lastFrame = anim->firstFrame;
02831 firstFrame = anim->firstFrame + anim->numFrames;
02832 }
02833 else
02834 {
02835 firstFrame = anim->firstFrame;
02836 lastFrame = anim->firstFrame + anim->numFrames;
02837 }
02838
02839 if (cg_animBlend.integer)
02840 {
02841 flags |= BONE_ANIM_BLEND;
02842 }
02843
02844 if (BG_InDeathAnim(newAnimation))
02845 {
02846 flags &= ~BONE_ANIM_BLEND;
02847 }
02848 else if ( oldAnim != -1 &&
02849 BG_InDeathAnim(oldAnim))
02850 {
02851 flags &= ~BONE_ANIM_BLEND;
02852 }
02853
02854 if (flags & BONE_ANIM_BLEND)
02855 {
02856 if (BG_FlippingAnim(newAnimation))
02857 {
02858 blendTime = 200;
02859 }
02860 else if ( oldAnim != -1 &&
02861 (BG_FlippingAnim(oldAnim)) )
02862 {
02863 blendTime = 200;
02864 }
02865 }
02866
02867 animSpeed *= animSpeedMult;
02868
02869 BG_SaberStartTransAnim(cent->currentState.number, cent->currentState.fireflag, cent->currentState.weapon, newAnimation, &animSpeed, cent->currentState.brokenLimbs);
02870
02871 if (torsoOnly)
02872 {
02873 if (lf->animationTorsoSpeed != animSpeedMult && newAnimation == oldAnim &&
02874 flipState == lf->lastFlip)
02875 {
02876 resumeFrame = qtrue;
02877 }
02878 lf->animationTorsoSpeed = animSpeedMult;
02879 }
02880 else
02881 {
02882 if (lf->animationSpeed != animSpeedMult && newAnimation == oldAnim &&
02883 flipState == lf->lastFlip)
02884 {
02885 resumeFrame = qtrue;
02886 }
02887 lf->animationSpeed = animSpeedMult;
02888 }
02889
02890
02891 if ( cent->currentState.NPC_class == CLASS_VEHICLE )
02892 {
02893 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", firstFrame, lastFrame, flags, animSpeed,cg.time, beginFrame, blendTime);
02894 return;
02895 }
02896
02897 if (torsoOnly && !cent->noLumbar)
02898 {
02899 float GBAcFrame = 0;
02900 if (resumeFrame)
02901 {
02902 trap_G2API_GetBoneFrame(cent->ghoul2, "lower_lumbar", cg.time, &GBAcFrame, NULL, 0);
02903 beginFrame = GBAcFrame;
02904 }
02905
02906
02907 trap_G2API_GetBoneFrame(cent->ghoul2, "model_root", cg.time, &GBAcFrame, NULL, 0);
02908
02909 if ((cent->currentState.torsoAnim) == (cent->currentState.legsAnim) && GBAcFrame >= anim->firstFrame && GBAcFrame <= (anim->firstFrame + anim->numFrames))
02910 {
02911 beginFrame = GBAcFrame;
02912 }
02913
02914 if (firstFrame > lastFrame || ci->torsoAnim == newAnimation)
02915 {
02916 beginFrame = -1;
02917 }
02918
02919 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "lower_lumbar", firstFrame, lastFrame, flags, animSpeed,cg.time, beginFrame, blendTime);
02920
02921
02922 cent->pe.torso.frame = firstFrame;
02923
02924 if (ci)
02925 {
02926 ci->torsoAnim = newAnimation;
02927 }
02928 }
02929 else
02930 {
02931 if (resumeFrame)
02932 {
02933 float GBAcFrame = 0;
02934 trap_G2API_GetBoneFrame(cent->ghoul2, "model_root", cg.time, &GBAcFrame, NULL, 0);
02935 beginFrame = GBAcFrame;
02936 }
02937
02938 if ((beginFrame < firstFrame) || (beginFrame > lastFrame))
02939 {
02940 beginFrame = -1;
02941 }
02942
02943 if (cent->currentState.torsoAnim == cent->currentState.legsAnim &&
02944 (ci->legsAnim != newAnimation || oldSpeed != animSpeed))
02945 {
02946 float GBAcFrame = 0;
02947 int oldBeginFrame = beginFrame;
02948
02949 trap_G2API_GetBoneFrame(cent->ghoul2, "lower_lumbar", cg.time, &GBAcFrame, NULL, 0);
02950 beginFrame = GBAcFrame;
02951 if ((beginFrame < firstFrame) || (beginFrame > lastFrame))
02952 {
02953 beginFrame = oldBeginFrame;
02954 }
02955 }
02956
02957 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", firstFrame, lastFrame, flags, animSpeed, cg.time, beginFrame, blendTime);
02958
02959 if (ci)
02960 {
02961 ci->legsAnim = newAnimation;
02962 }
02963 }
02964
02965 if (cent->localAnimIndex <= 1 && (cent->currentState.torsoAnim) == newAnimation && !cent->noLumbar)
02966 {
02967 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", firstFrame, lastFrame, flags, animSpeed, cg.time, beginFrame, blendTime);
02968 }
02969
02970 #if 0 //disabled for now
02971 if (cent->localAnimIndex <= 1 && cent->currentState.brokenLimbs &&
02972 (cent->currentState.brokenLimbs & (1 << BROKENLIMB_LARM)))
02973 {
02974 char *brokenBone = "lhumerus";
02975 animation_t *armAnim;
02976 int armFirstFrame;
02977 int armLastFrame;
02978 int armFlags = 0;
02979 float armAnimSpeed;
02980
02981 armAnim = &bgAllAnims[cent->localAnimIndex].anims[ BOTH_DEAD21 ];
02982 ci->brokenLimbs = cent->currentState.brokenLimbs;
02983
02984 armFirstFrame = armAnim->firstFrame;
02985 armLastFrame = armAnim->firstFrame+armAnim->numFrames;
02986 armAnimSpeed = 50.0f / armAnim->frameLerp;
02987 armFlags = BONE_ANIM_OVERRIDE_LOOP;
02988
02989 if (cg_animBlend.integer)
02990 {
02991 armFlags |= BONE_ANIM_BLEND;
02992 }
02993
02994 trap_G2API_SetBoneAnim(cent->ghoul2, 0, brokenBone, armFirstFrame, armLastFrame, armFlags, armAnimSpeed, cg.time, -1, blendTime);
02995 }
02996 else if (cent->localAnimIndex <= 1 && cent->currentState.brokenLimbs &&
02997 (cent->currentState.brokenLimbs & (1 << BROKENLIMB_RARM)))
02998 {
02999 char *brokenBone = "rhumerus";
03000 char *supportBone = "lhumerus";
03001
03002 ci->brokenLimbs = cent->currentState.brokenLimbs;
03003
03004
03005
03006 if ((
03007 cent->currentState.weapon != WP_SABER ||
03008 BG_SaberStanceAnim(newAnimation) ||
03009 PM_RunningAnim(newAnimation)) &&
03010 cent->currentState.torsoAnim == newAnimation &&
03011 (!ci->saber[1].model[0] || cent->currentState.weapon != WP_SABER))
03012 {
03013 int armFirstFrame;
03014 int armLastFrame;
03015 int armFlags = 0;
03016 float armAnimSpeed;
03017 animation_t *armAnim;
03018
03019 if (cent->currentState.weapon == WP_MELEE ||
03020 cent->currentState.weapon == WP_SABER ||
03021 cent->currentState.weapon == WP_BRYAR_PISTOL)
03022 {
03023 armAnim = &bgAllAnims[cent->localAnimIndex].anims[ BOTH_ATTACK2 ];
03024
03025
03026 armFirstFrame = armAnim->firstFrame+armAnim->numFrames;
03027 armLastFrame = armAnim->firstFrame+armAnim->numFrames;
03028 armAnimSpeed = 50.0f / armAnim->frameLerp;
03029 armFlags = BONE_ANIM_OVERRIDE_LOOP;
03030
03031
03032
03033
03034
03035
03036
03037
03038
03039 trap_G2API_SetBoneAnim(cent->ghoul2, 0, brokenBone, armFirstFrame, armLastFrame, armFlags, armAnimSpeed, cg.time, -1, 0);
03040 }
03041 else
03042 {
03043 trap_G2API_SetBoneAnim(cent->ghoul2, 0, brokenBone, firstFrame, lastFrame, flags, animSpeed, cg.time, beginFrame, blendTime);
03044 }
03045
03046 if (newAnimation != BOTH_MELEE1 &&
03047 newAnimation != BOTH_MELEE2 &&
03048 (newAnimation == TORSO_WEAPONREADY2 || newAnimation == BOTH_ATTACK2 || cent->currentState.weapon < WP_BRYAR_PISTOL))
03049 {
03050
03051 armAnim = &bgAllAnims[cent->localAnimIndex].anims[ BOTH_STAND2 ];
03052 armFirstFrame = armAnim->firstFrame;
03053 armLastFrame = armAnim->firstFrame+armAnim->numFrames;
03054 armAnimSpeed = 50.0f / armAnim->frameLerp;
03055 armFlags = BONE_ANIM_OVERRIDE_LOOP;
03056
03057 if (cg_animBlend.integer)
03058 {
03059 armFlags |= BONE_ANIM_BLEND;
03060 }
03061
03062 trap_G2API_SetBoneAnim(cent->ghoul2, 0, supportBone, armFirstFrame, armLastFrame, armFlags, armAnimSpeed, cg.time, -1, 150);
03063 }
03064 else
03065 {
03066 trap_G2API_SetBoneAnim(cent->ghoul2, 0, supportBone, firstFrame, lastFrame, flags, animSpeed, cg.time, beginFrame, blendTime);
03067 }
03068 }
03069 else if (cent->currentState.torsoAnim == newAnimation)
03070 {
03071 trap_G2API_SetBoneAnim(cent->ghoul2, 0, brokenBone, firstFrame, lastFrame, flags, animSpeed, cg.time, beginFrame, blendTime);
03072 trap_G2API_SetBoneAnim(cent->ghoul2, 0, supportBone, firstFrame, lastFrame, flags, animSpeed, cg.time, beginFrame, blendTime);
03073 }
03074 }
03075 else if (ci &&
03076 (ci->brokenLimbs ||
03077 trap_G2API_GetBoneFrame(cent->ghoul2, "lhumerus", cg.time, &unused, cgs.gameModels, 0) ||
03078 trap_G2API_GetBoneFrame(cent->ghoul2, "rhumerus", cg.time, &unused, cgs.gameModels, 0)))
03079
03080 {
03081 char *brokenBone = NULL;
03082 int broken = 0;
03083
03084
03085
03086 if (ci->brokenLimbs & (1<<BROKENLIMB_LARM))
03087 {
03088 brokenBone = "lhumerus";
03089 broken |= (1<<BROKENLIMB_LARM);
03090 }
03091 else if (ci->brokenLimbs & (1<<BROKENLIMB_RARM))
03092 {
03093 brokenBone = "rhumerus";
03094 broken |= (1<<BROKENLIMB_RARM);
03095
03096
03097 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "lhumerus", 0, 1, 0, 0, cg.time, -1, 0);
03098 if (!trap_G2API_RemoveBone(cent->ghoul2, "lhumerus", 0))
03099 {
03100 assert(0);
03101 Com_Printf("WARNING: Failed to remove lhumerus\n");
03102 }
03103 }
03104
03105 if (!brokenBone)
03106 {
03107 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "lhumerus", 0, 1, 0, 0, cg.time, -1, 0);
03108 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "rhumerus", 0, 1, 0, 0, cg.time, -1, 0);
03109 trap_G2API_RemoveBone(cent->ghoul2, "lhumerus", 0);
03110 trap_G2API_RemoveBone(cent->ghoul2, "rhumerus", 0);
03111 ci->brokenLimbs = 0;
03112 }
03113 else
03114 {
03115
03116 trap_G2API_SetBoneAnim(cent->ghoul2, 0, brokenBone, 0, 1, 0, 0, cg.time, -1, 0);
03117
03118
03119 if (!trap_G2API_RemoveBone(cent->ghoul2, brokenBone, 0))
03120 {
03121 assert(0);
03122 Com_Printf("WARNING: Failed to remove %s\n", brokenBone);
03123 }
03124 ci->brokenLimbs &= ~broken;
03125 }
03126 }
03127 #endif
03128 }
03129 }
03130
03131
03132
03133
03134
03135
03136
03137
03138
03139
03140
03141
03142
03143
03144 static qboolean CG_FirstAnimFrame(lerpFrame_t *lf, qboolean torsoOnly, float speedScale)
03145 {
03146 if (torsoOnly)
03147 {
03148 if (lf->animationTorsoSpeed == speedScale)
03149 {
03150 return qfalse;
03151 }
03152 }
03153 else
03154 {
03155 if (lf->animationSpeed == speedScale)
03156 {
03157 return qfalse;
03158 }
03159 }
03160
03161
03162
03163
03164
03165
03166
03167
03168
03169
03170
03171
03172
03173
03174 return qtrue;
03175 }
03176
03177
03178
03179
03180
03181
03182
03183
03184
03185 static void CG_RunLerpFrame( centity_t *cent, clientInfo_t *ci, lerpFrame_t *lf, qboolean flipState, int newAnimation, float speedScale, qboolean torsoOnly)
03186 {
03187
03188 if ( cg_animSpeed.integer == 0 ) {
03189 lf->oldFrame = lf->frame = lf->backlerp = 0;
03190 return;
03191 }
03192
03193
03194 if (cent->currentState.forceFrame)
03195 {
03196 if (lf->lastForcedFrame != cent->currentState.forceFrame)
03197 {
03198 int flags = BONE_ANIM_OVERRIDE_FREEZE|BONE_ANIM_BLEND;
03199 float animSpeed = 1.0f;
03200 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "lower_lumbar", cent->currentState.forceFrame, cent->currentState.forceFrame+1, flags, animSpeed, cg.time, -1, 150);
03201 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", cent->currentState.forceFrame, cent->currentState.forceFrame+1, flags, animSpeed, cg.time, -1, 150);
03202 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", cent->currentState.forceFrame, cent->currentState.forceFrame+1, flags, animSpeed, cg.time, -1, 150);
03203 }
03204
03205 lf->lastForcedFrame = cent->currentState.forceFrame;
03206
03207 lf->animationNumber = 0;
03208 }
03209 else
03210 {
03211 lf->lastForcedFrame = -1;
03212
03213 if ( (newAnimation != lf->animationNumber || cent->currentState.brokenLimbs != ci->brokenLimbs || lf->lastFlip != flipState || !lf->animation) || (CG_FirstAnimFrame(lf, torsoOnly, speedScale)) )
03214 {
03215 CG_SetLerpFrameAnimation( cent, ci, lf, newAnimation, speedScale, torsoOnly, flipState);
03216 }
03217 }
03218
03219 lf->lastFlip = flipState;
03220
03221 if ( lf->frameTime > cg.time + 200 ) {
03222 lf->frameTime = cg.time;
03223 }
03224
03225 if ( lf->oldFrameTime > cg.time ) {
03226 lf->oldFrameTime = cg.time;
03227 }
03228
03229
03230 if ( lf->frameTime == lf->oldFrameTime ) {
03231 lf->backlerp = 0;
03232 } else {
03233 lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
03234 }
03235 }
03236
03237
03238
03239
03240
03241
03242
03243 static void CG_ClearLerpFrame( centity_t *cent, clientInfo_t *ci, lerpFrame_t *lf, int animationNumber, qboolean torsoOnly) {
03244 lf->frameTime = lf->oldFrameTime = cg.time;
03245 CG_SetLerpFrameAnimation( cent, ci, lf, animationNumber, 1, torsoOnly, qfalse );
03246
03247 if ( lf->animation->frameLerp < 0 )
03248 {
03249 lf->oldFrame = lf->frame = (lf->animation->firstFrame + lf->animation->numFrames);
03250 }
03251 else
03252 {
03253 lf->oldFrame = lf->frame = lf->animation->firstFrame;
03254 }
03255 }
03256
03257
03258
03259
03260
03261
03262
03263 #include "../namespace_begin.h"
03264 qboolean PM_WalkingAnim( int anim );
03265 #include "../namespace_end.h"
03266
03267 static void CG_PlayerAnimation( centity_t *cent, int *legsOld, int *legs, float *legsBackLerp,
03268 int *torsoOld, int *torso, float *torsoBackLerp ) {
03269 clientInfo_t *ci;
03270 int clientNum;
03271 float speedScale;
03272
03273 clientNum = cent->currentState.clientNum;
03274
03275 if ( cg_noPlayerAnims.integer ) {
03276 *legsOld = *legs = *torsoOld = *torso = 0;
03277 return;
03278 }
03279
03280 if (!PM_RunningAnim(cent->currentState.legsAnim) &&
03281 !PM_WalkingAnim(cent->currentState.legsAnim))
03282 {
03283 speedScale = 1.0f;
03284 }
03285 else if (cent->currentState.forcePowersActive & (1 << FP_RAGE))
03286 {
03287 speedScale = 1.3f;
03288 }
03289 else if (cent->currentState.forcePowersActive & (1 << FP_SPEED))
03290 {
03291 speedScale = 1.7f;
03292 }
03293 else
03294 {
03295 speedScale = 1.0f;
03296 }
03297
03298 if (cent->currentState.eType == ET_NPC)
03299 {
03300 ci = cent->npcClient;
03301 assert(ci);
03302 }
03303 else
03304 {
03305 ci = &cgs.clientinfo[ clientNum ];
03306 }
03307
03308 CG_RunLerpFrame( cent, ci, ¢->pe.legs, cent->currentState.legsFlip, cent->currentState.legsAnim, speedScale, qfalse);
03309
03310 if (!(cent->currentState.forcePowersActive & (1 << FP_RAGE)))
03311 {
03312 speedScale = 1.0f;
03313 }
03314 else
03315 {
03316 speedScale = 1.7f;
03317 }
03318
03319 *legsOld = cent->pe.legs.oldFrame;
03320 *legs = cent->pe.legs.frame;
03321 *legsBackLerp = cent->pe.legs.backlerp;
03322
03323
03324 if ( cent->currentState.NPC_class != CLASS_VEHICLE )
03325 {
03326 CG_RunLerpFrame( cent, ci, ¢->pe.torso, cent->currentState.torsoFlip, cent->currentState.torsoAnim, speedScale, qtrue );
03327
03328 *torsoOld = cent->pe.torso.oldFrame;
03329 *torso = cent->pe.torso.frame;
03330 *torsoBackLerp = cent->pe.torso.backlerp;
03331 }
03332 }
03333
03334
03335
03336
03337
03338
03339
03340
03341
03342
03343
03344
03345 #if 0
03346 typedef struct boneAngleParms_s {
03347 void *ghoul2;
03348 int modelIndex;
03349 char *boneName;
03350 vec3_t angles;
03351 int flags;
03352 int up;
03353 int right;
03354 int forward;
03355 qhandle_t *modelList;
03356 int blendTime;
03357 int currentTime;
03358
03359 qboolean refreshSet;
03360 } boneAngleParms_t;
03361
03362 boneAngleParms_t cgBoneAnglePostSet;
03363 #endif
03364
03365 void CG_G2SetBoneAngles(void *ghoul2, int modelIndex, const char *boneName, const vec3_t angles, const int flags,
03366 const int up, const int right, const int forward, qhandle_t *modelList,
03367 int blendTime , int currentTime )
03368 {
03369
03370 #if 0
03371
03372
03373 memset(&cgBoneAnglePostSet, 0, sizeof(cgBoneAnglePostSet));
03374 cgBoneAnglePostSet.ghoul2 = ghoul2;
03375 cgBoneAnglePostSet.modelIndex = modelIndex;
03376 cgBoneAnglePostSet.boneName = (char *)boneName;
03377
03378 cgBoneAnglePostSet.angles[0] = angles[0];
03379 cgBoneAnglePostSet.angles[1] = angles[1];
03380 cgBoneAnglePostSet.angles[2] = angles[2];
03381
03382 cgBoneAnglePostSet.flags = flags;
03383 cgBoneAnglePostSet.up = up;
03384 cgBoneAnglePostSet.right = right;
03385 cgBoneAnglePostSet.forward = forward;
03386 cgBoneAnglePostSet.modelList = modelList;
03387 cgBoneAnglePostSet.blendTime = blendTime;
03388 cgBoneAnglePostSet.currentTime = currentTime;
03389
03390 cgBoneAnglePostSet.refreshSet = qtrue;
03391 #endif
03392
03393
03394 trap_G2API_SetBoneAngles(ghoul2, modelIndex, boneName, angles, flags, up, right, forward, modelList,
03395 blendTime, currentTime);
03396 }
03397
03398
03399
03400
03401
03402
03403
03404
03405
03406
03407 void CG_Rag_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
03408 int skipNumber, int mask ) {
03409 trap_CM_BoxTrace ( result, start, end, mins, maxs, 0, mask);
03410 result->entityNum = result->fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
03411 }
03412
03413
03414
03415 #ifdef _RAG_BOLT_TESTING
03416 void CG_TempTestFunction(centity_t *cent, vec3_t forcedAngles)
03417 {
03418 mdxaBone_t boltMatrix;
03419 vec3_t tAngles;
03420 vec3_t bOrg;
03421 vec3_t bDir;
03422 vec3_t uOrg;
03423
03424 VectorSet(tAngles, 0, cent->lerpAngles[YAW], 0);
03425
03426 trap_G2API_GetBoltMatrix(cent->ghoul2, 1, 0, &boltMatrix, tAngles, cent->lerpOrigin,
03427 cg.time, cgs.gameModels, cent->modelScale);
03428 BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, bOrg);
03429 BG_GiveMeVectorFromMatrix(&boltMatrix, NEGATIVE_Y, bDir);
03430
03431 VectorMA(bOrg, 40, bDir, uOrg);
03432
03433 CG_TestLine(bOrg, uOrg, 50, 0x0000ff, 1);
03434
03435 cent->turAngles[YAW] = forcedAngles[YAW];
03436 }
03437 #endif
03438
03439
03440 static const char *cg_effectorStringTable[] =
03441 {
03442
03443
03444 "lhand",
03445 "rtibia",
03446 "ltibia",
03447 "rtalus",
03448 "ltalus",
03449
03450 "lradiusX",
03451 "rfemurX",
03452 "lfemurX",
03453
03454 NULL
03455 };
03456
03457
03458
03459
03460 static int CG_RagAnimForPositioning(centity_t *cent)
03461 {
03462 int bolt;
03463 vec3_t dir;
03464 mdxaBone_t matrix;
03465
03466 assert(cent->ghoul2);
03467 bolt = trap_G2API_AddBolt(cent->ghoul2, 0, "pelvis");
03468 assert(bolt > -1);
03469
03470 trap_G2API_GetBoltMatrix(cent->ghoul2, 0, bolt, &matrix, cent->turAngles, cent->lerpOrigin,
03471 cg.time, cgs.gameModels, cent->modelScale);
03472 BG_GiveMeVectorFromMatrix(&matrix, NEGATIVE_Z, dir);
03473
03474 if (dir[2] > 0.0f)
03475 {
03476 return BOTH_DEADFLOP2;
03477 }
03478 else
03479 {
03480 return BOTH_DEADFLOP1;
03481 }
03482 }
03483
03484
03485
03486 qboolean CG_RagDoll(centity_t *cent, vec3_t forcedAngles)
03487 {
03488 vec3_t usedOrg;
03489 qboolean inSomething = qfalse;
03490 int ragAnim;
03491
03492 if (!cg_ragDoll.integer)
03493 {
03494 return qfalse;
03495 }
03496
03497 if (cent->localAnimIndex)
03498 {
03499 return qfalse;
03500 }
03501
03502 VectorCopy(cent->lerpOrigin, usedOrg);
03503
03504 if (!cent->isRagging)
03505 {
03506 if (cent->currentState.eFlags & EF_RAG)
03507 {
03508 inSomething = qtrue;
03509 }
03510 else if (cent->currentState.groundEntityNum == ENTITYNUM_NONE)
03511 {
03512 vec3_t cVel;
03513
03514 VectorCopy(cent->currentState.pos.trDelta, cVel);
03515
03516 if (VectorNormalize(cVel) > 400)
03517 {
03518 inSomething = qtrue;
03519 }
03520 }
03521
03522 if (cent->currentState.eType == ET_BODY)
03523 {
03524 if (cent->ownerRagging)
03525 {
03526 cent->isRagging = qtrue;
03527 return qfalse;
03528 }
03529 }
03530
03531 if (cg_ragDoll.integer > 1)
03532 {
03533 inSomething = qtrue;
03534 }
03535
03536 if (!inSomething)
03537 {
03538 int anim = (cent->currentState.legsAnim);
03539 int dur = (bgAllAnims[cent->localAnimIndex].anims[anim].numFrames-1) * fabs((float)(bgAllAnims[cent->localAnimIndex].anims[anim].frameLerp));
03540 int i = 0;
03541 int boltChecks[5];
03542 vec3_t boltPoints[5];
03543 vec3_t trStart, trEnd;
03544 vec3_t tAng;
03545 qboolean deathDone = qfalse;
03546 trace_t tr;
03547 mdxaBone_t boltMatrix;
03548
03549 VectorSet( tAng, cent->turAngles[PITCH], cent->turAngles[YAW], cent->turAngles[ROLL] );
03550
03551 if (cent->pe.legs.animationTime > 50 && (cg.time - cent->pe.legs.animationTime) > dur)
03552 {
03553 deathDone = qtrue;
03554 }
03555
03556 if (deathDone)
03557 {
03558 boltChecks[0] = trap_G2API_AddBolt(cent->ghoul2, 0, "rhand");
03559 boltChecks[1] = trap_G2API_AddBolt(cent->ghoul2, 0, "lhand");
03560 }
03561 else
03562 {
03563 i = 2;
03564 }
03565 boltChecks[2] = trap_G2API_AddBolt(cent->ghoul2, 0, "cranium");
03566
03567
03568 boltChecks[3] = trap_G2API_AddBolt(cent->ghoul2, 0, "rtalus");
03569 boltChecks[4] = trap_G2API_AddBolt(cent->ghoul2, 0, "ltalus");
03570
03571
03572
03573 trap_G2API_GetBoltMatrix(cent->ghoul2, 0, boltChecks[2], &boltMatrix, tAng, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale);
03574 BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, boltPoints[2]);
03575
03576 while (i < 5)
03577 {
03578 if (i < 2)
03579 {
03580 trap_G2API_GetBoltMatrix(cent->ghoul2, 0, boltChecks[i], &boltMatrix, tAng, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale);
03581 BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, boltPoints[i]);
03582 VectorCopy(boltPoints[i], trStart);
03583 VectorCopy(boltPoints[2], trEnd);
03584 }
03585 else
03586 {
03587 if (i > 2)
03588 {
03589 trap_G2API_GetBoltMatrix(cent->ghoul2, 0, boltChecks[i], &boltMatrix, tAng, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale);
03590 BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, boltPoints[i]);
03591 }
03592 VectorCopy(boltPoints[i], trStart);
03593 VectorCopy(cent->lerpOrigin, trEnd);
03594 }
03595
03596
03597 CG_Rag_Trace(&tr, trStart, NULL, NULL, trEnd, cent->currentState.number, MASK_SOLID);
03598
03599 if (tr.fraction != 1.0 || tr.startsolid || tr.allsolid)
03600 {
03601
03602
03603 #if 0
03604 vec3_t vSub;
03605
03606
03607 VectorSubtract(boltPoints[2], boltPoints[3], vSub);
03608 VectorNormalize(vSub);
03609 vectoangles(vSub, vSub);
03610
03611 if (deathDone || (vSub[PITCH] < 50 && vSub[PITCH] > -50))
03612 {
03613 inSomething = qtrue;
03614 }
03615 #else
03616 inSomething = qtrue;
03617 #endif
03618 break;
03619 }
03620
03621 i++;
03622 }
03623 }
03624
03625 if (inSomething)
03626 {
03627 cent->isRagging = qtrue;
03628 #if 0
03629 VectorClear(cent->lerpOriginOffset);
03630 #endif
03631 }
03632 }
03633
03634 if (cent->isRagging)
03635 {
03636 sharedRagDollParams_t tParms;
03637 sharedRagDollUpdateParams_t tuParms;
03638
03639 ragAnim = CG_RagAnimForPositioning(cent);
03640
03641 if (cent->ikStatus)
03642 {
03643 trap_G2API_SetBoneIKState(cent->ghoul2, cg.time, NULL, IKS_NONE, NULL);
03644 cent->ikStatus = qfalse;
03645 }
03646
03647
03648 tParms.startFrame = bgAllAnims[cent->localAnimIndex].anims[ragAnim].firstFrame;
03649 tParms.endFrame = bgAllAnims[cent->localAnimIndex].anims[ragAnim].firstFrame + bgAllAnims[cent->localAnimIndex].anims[ragAnim].numFrames;
03650 #if 0
03651 {
03652 float animSpeed = 0;
03653 int blendTime = 600;
03654 int flags = 0;
03655
03656 if (bgAllAnims[cent->localAnimIndex].anims[ragAnim].loopFrames != -1)
03657 {
03658 flags = BONE_ANIM_OVERRIDE_LOOP;
03659 }
03660
03661
03662
03663
03664
03665
03666
03667
03668 animSpeed = 50.0f / bgAllAnims[cent->localAnimIndex].anims[ragAnim].frameLerp;
03669 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "lower_lumbar", tParms.startFrame, tParms.endFrame, flags, animSpeed,cg.time, -1, blendTime);
03670 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", tParms.startFrame, tParms.endFrame, flags, animSpeed, cg.time, -1, blendTime);
03671 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", tParms.startFrame, tParms.endFrame, flags, animSpeed, cg.time, -1, blendTime);
03672 }
03673 #elif 1 //with my new method of doing things I want it to continue the anim
03674 {
03675 float currentFrame;
03676 int startFrame, endFrame;
03677 int flags;
03678 float animSpeed;
03679
03680 if (trap_G2API_GetBoneAnim(cent->ghoul2, "model_root", cg.time, ¤tFrame, &startFrame, &endFrame, &flags, &animSpeed, cgs.gameModels, 0))
03681 {
03682 int blendTime = 500;
03683 animation_t *curAnim = &bgAllAnims[cent->localAnimIndex].anims[cent->currentState.legsAnim];
03684
03685 if (currentFrame >= (curAnim->firstFrame + curAnim->numFrames-1))
03686 {
03687 currentFrame = (curAnim->firstFrame + curAnim->numFrames-2);
03688 }
03689
03690 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "lower_lumbar", currentFrame, currentFrame+1, flags, animSpeed,cg.time, currentFrame, blendTime);
03691 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", currentFrame, currentFrame+1, flags, animSpeed, cg.time, currentFrame, blendTime);
03692 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", currentFrame, currentFrame+1, flags, animSpeed, cg.time, currentFrame, blendTime);
03693 }
03694 }
03695 #endif
03696 CG_G2SetBoneAngles(cent->ghoul2, 0, "upper_lumbar", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time);
03697 CG_G2SetBoneAngles(cent->ghoul2, 0, "lower_lumbar", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time);
03698 CG_G2SetBoneAngles(cent->ghoul2, 0, "thoracic", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time);
03699 CG_G2SetBoneAngles(cent->ghoul2, 0, "cervical", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, cgs.gameModels, 0, cg.time);
03700
03701 VectorCopy(forcedAngles, tParms.angles);
03702 VectorCopy(usedOrg, tParms.position);
03703 VectorCopy(cent->modelScale, tParms.scale);
03704 tParms.me = cent->currentState.number;
03705
03706 tParms.collisionType = 1;
03707 tParms.RagPhase = RP_DEATH_COLLISION;
03708 tParms.fShotStrength = 4;
03709
03710 trap_G2API_SetRagDoll(cent->ghoul2, &tParms);
03711
03712 VectorCopy(forcedAngles, tuParms.angles);
03713 VectorCopy(usedOrg, tuParms.position);
03714 VectorCopy(cent->modelScale, tuParms.scale);
03715 tuParms.me = cent->currentState.number;
03716 tuParms.settleFrame = tParms.endFrame-1;
03717
03718 if (cent->currentState.groundEntityNum != ENTITYNUM_NONE)
03719 {
03720 VectorClear(tuParms.velocity);
03721 }
03722 else
03723 {
03724 VectorScale(cent->currentState.pos.trDelta, 2.0f, tuParms.velocity);
03725 }
03726
03727 trap_G2API_AnimateG2Models(cent->ghoul2, cg.time, &tuParms);
03728
03729
03730 cent->turAngles[YAW] =
03731 cent->lerpAngles[YAW] =
03732 cent->pe.torso.yawAngle =
03733 cent->pe.legs.yawAngle = forcedAngles[YAW];
03734
03735 if (cent->currentState.ragAttach &&
03736 (cent->currentState.eType != ET_NPC || cent->currentState.NPC_class != CLASS_VEHICLE))
03737 {
03738 centity_t *grabEnt;
03739
03740 if (cent->currentState.ragAttach == ENTITYNUM_NONE)
03741 {
03742 grabEnt = &cg_entities[0];
03743 }
03744 else
03745 {
03746 grabEnt = &cg_entities[cent->currentState.ragAttach];
03747 }
03748
03749 if (grabEnt->ghoul2)
03750 {
03751 mdxaBone_t matrix;
03752 vec3_t bOrg;
03753 vec3_t thisHand;
03754 vec3_t hands;
03755 vec3_t pcjMin, pcjMax;
03756 vec3_t pDif;
03757 vec3_t thorPoint;
03758 float difLen;
03759 int thorBolt;
03760
03761
03762 trap_G2API_GetBoltMatrix(grabEnt->ghoul2, 0, 0, &matrix, grabEnt->turAngles, grabEnt->lerpOrigin,
03763 cg.time, cgs.gameModels, grabEnt->modelScale);
03764 BG_GiveMeVectorFromMatrix(&matrix, ORIGIN, bOrg);
03765
03766
03767 trap_G2API_GetBoltMatrix(cent->ghoul2, 0, 0, &matrix, cent->turAngles, cent->lerpOrigin,
03768 cg.time, cgs.gameModels, cent->modelScale);
03769 BG_GiveMeVectorFromMatrix(&matrix, ORIGIN, thisHand);
03770
03771
03772 thorBolt = trap_G2API_AddBolt(cent->ghoul2, 0, "thoracic");
03773 trap_G2API_GetBoltMatrix(cent->ghoul2, 0, thorBolt, &matrix, cent->turAngles, cent->lerpOrigin,
03774 cg.time, cgs.gameModels, cent->modelScale);
03775 BG_GiveMeVectorFromMatrix(&matrix, ORIGIN, thorPoint);
03776
03777 VectorSubtract(bOrg, thisHand, hands);
03778
03779 if (VectorLength(hands) < 3.0f)
03780 {
03781 trap_G2API_RagForceSolve(cent->ghoul2, qfalse);
03782 }
03783 else
03784 {
03785 trap_G2API_RagForceSolve(cent->ghoul2, qtrue);
03786 }
03787
03788
03789 trap_G2API_RagEffectorGoal(cent->ghoul2, "rhand", bOrg);
03790 trap_G2API_RagEffectorGoal(cent->ghoul2, "rradius", bOrg);
03791 trap_G2API_RagEffectorGoal(cent->ghoul2, "rradiusX", bOrg);
03792 trap_G2API_RagEffectorGoal(cent->ghoul2, "rhumerusX", bOrg);
03793 trap_G2API_RagEffectorGoal(cent->ghoul2, "rhumerus", bOrg);
03794
03795
03796 trap_G2API_RagPCJGradientSpeed(cent->ghoul2, "rhumerus", 1.5f);
03797 trap_G2API_RagPCJGradientSpeed(cent->ghoul2, "rradius", 1.5f);
03798
03799
03800 VectorSet(pcjMin, -999, -999, -999);
03801 VectorSet(pcjMax, 999, 999, 999);
03802 trap_G2API_RagPCJConstraint(cent->ghoul2, "rhumerus", pcjMin, pcjMax);
03803 trap_G2API_RagPCJConstraint(cent->ghoul2, "rradius", pcjMin, pcjMax);
03804
03805 cent->overridingBones = cg.time + 2000;
03806
03807
03808 VectorSubtract(bOrg, thorPoint, hands);
03809 VectorNormalize(hands);
03810 VectorScale(hands, 2048.0f, hands);
03811 trap_G2API_RagEffectorKick(cent->ghoul2, "thoracic", hands);
03812 trap_G2API_RagEffectorKick(cent->ghoul2, "ceyebrow", hands);
03813
03814 VectorSubtract(cent->ragLastOrigin, cent->lerpOrigin, pDif);
03815 VectorCopy(cent->lerpOrigin, cent->ragLastOrigin);
03816
03817 if (cent->ragLastOriginTime >= cg.time && cent->currentState.groundEntityNum != ENTITYNUM_NONE)
03818 {
03819 difLen = VectorLength(pDif);
03820 if (difLen > 0.0f)
03821 {
03822 vec3_t dVel;
03823 vec3_t rVel;
03824 int i = 0;
03825
03826 if (difLen < 12.0f)
03827 {
03828 VectorScale(pDif, 12.0f/difLen, pDif);
03829 difLen = 12.0f;
03830 }
03831
03832 while (cg_effectorStringTable[i])
03833 {
03834 VectorCopy(pDif, dVel);
03835 dVel[2] = 0;
03836
03837
03838 VectorSet(rVel, flrand(-0.1f, 0.1f), flrand(-0.1f, 0.1f), flrand(0.1f, 0.5));
03839 VectorScale(rVel, 8.0f, rVel);
03840
03841 VectorAdd(dVel, rVel, dVel);
03842 VectorScale(dVel, 10.0f, dVel);
03843
03844 trap_G2API_RagEffectorKick(cent->ghoul2, cg_effectorStringTable[i], dVel);
03845
03846 #if 0
03847 {
03848 mdxaBone_t bm;
03849 vec3_t borg;
03850 vec3_t vorg;
03851 int b = trap_G2API_AddBolt(cent->ghoul2, 0, cg_effectorStringTable[i]);
03852
03853 trap_G2API_GetBoltMatrix(cent->ghoul2, 0, b, &bm, cent->turAngles, cent->lerpOrigin, cg.time,
03854 cgs.gameModels, cent->modelScale);
03855 BG_GiveMeVectorFromMatrix(&bm, ORIGIN, borg);
03856
03857 VectorMA(borg, 1.0f, dVel, vorg);
03858
03859 CG_TestLine(borg, vorg, 50, 0x0000ff, 1);
03860 }
03861 #endif
03862
03863 i++;
03864 }
03865 }
03866 }
03867 cent->ragLastOriginTime = cg.time + 1000;
03868 }
03869 }
03870 else if (cent->overridingBones)
03871 {
03872 vec3_t pcjMin, pcjMax;
03873 vec3_t dVel;
03874
03875
03876 trap_G2API_RagEffectorGoal(cent->ghoul2, "rhand", NULL);
03877 trap_G2API_RagEffectorGoal(cent->ghoul2, "rradius", NULL);
03878 trap_G2API_RagEffectorGoal(cent->ghoul2, "rradiusX", NULL);
03879 trap_G2API_RagEffectorGoal(cent->ghoul2, "rhumerusX", NULL);
03880 trap_G2API_RagEffectorGoal(cent->ghoul2, "rhumerus", NULL);
03881
03882 VectorSet(dVel, 0.0f, 0.0f, -64.0f);
03883 trap_G2API_RagEffectorKick(cent->ghoul2, "rhand", dVel);
03884
03885 trap_G2API_RagPCJGradientSpeed(cent->ghoul2, "rhumerus", 0.0f);
03886 trap_G2API_RagPCJGradientSpeed(cent->ghoul2, "rradius", 0.0f);
03887
03888 VectorSet(pcjMin,-100.0f,-40.0f,-15.0f);
03889 VectorSet(pcjMax,-15.0f,80.0f,15.0f);
03890 trap_G2API_RagPCJConstraint(cent->ghoul2, "rhumerus", pcjMin, pcjMax);
03891
03892 VectorSet(pcjMin,-25.0f,-20.0f,-20.0f);
03893 VectorSet(pcjMax,90.0f,20.0f,-20.0f);
03894 trap_G2API_RagPCJConstraint(cent->ghoul2, "rradius", pcjMin, pcjMax);
03895
03896 if (cent->overridingBones < cg.time)
03897 {
03898 trap_G2API_RagForceSolve(cent->ghoul2, qfalse);
03899 cent->overridingBones = 0;
03900 }
03901 else
03902 {
03903 trap_G2API_RagForceSolve(cent->ghoul2, qtrue);
03904 }
03905 }
03906
03907 return qtrue;
03908 }
03909
03910 return qfalse;
03911 }
03912
03913
03914 void CG_G2ServerBoneAngles(centity_t *cent)
03915 {
03916 int i = 0;
03917 int bone = cent->currentState.boneIndex1;
03918 int flags, up, right, forward;
03919 vec3_t boneAngles;
03920
03921 VectorCopy(cent->currentState.boneAngles1, boneAngles);
03922
03923 while (i < 4)
03924 {
03925 if (bone)
03926 {
03927 const char *boneName = CG_ConfigString(CS_G2BONES+bone);
03928
03929 if (boneName && boneName[0])
03930 {
03931 flags = BONE_ANGLES_POSTMULT;
03932
03933
03934 forward = (cent->currentState.boneOrient)&7;
03935 right = (cent->currentState.boneOrient>>3)&7;
03936 up = (cent->currentState.boneOrient>>6)&7;
03937
03938 trap_G2API_SetBoneAngles(cent->ghoul2, 0, boneName, boneAngles, flags, up, right, forward, cgs.gameModels, 100, cg.time);
03939 }
03940 }
03941
03942 switch (i)
03943 {
03944 case 0:
03945 bone = cent->currentState.boneIndex2;
03946 VectorCopy(cent->currentState.boneAngles2, boneAngles);
03947 break;
03948 case 1:
03949 bone = cent->currentState.boneIndex3;
03950 VectorCopy(cent->currentState.boneAngles3, boneAngles);
03951 break;
03952 case 2:
03953 bone = cent->currentState.boneIndex4;
03954 VectorCopy(cent->currentState.boneAngles4, boneAngles);
03955 break;
03956 default:
03957 break;
03958 }
03959
03960 i++;
03961 }
03962 }
03963
03964
03965
03966
03967
03968
03969 static void CG_G2SetHeadBlink( centity_t *cent, qboolean bStart )
03970 {
03971 vec3_t desiredAngles;
03972 int blendTime = 80;
03973 qboolean bWink = qfalse;
03974 const int hReye = trap_G2API_AddBolt( cent->ghoul2, 0, "reye" );
03975 const int hLeye = trap_G2API_AddBolt( cent->ghoul2, 0, "leye" );
03976
03977 if (hLeye == -1)
03978 {
03979 return;
03980 }
03981
03982 VectorClear(desiredAngles);
03983
03984 if (bStart)
03985 {
03986 desiredAngles[YAW] = -50;
03987 if ( random() > 0.95f )
03988 {
03989 bWink = qtrue;
03990 blendTime /=3;
03991 }
03992 }
03993 trap_G2API_SetBoneAngles( cent->ghoul2, 0, "leye", desiredAngles,
03994 BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL, blendTime, cg.time );
03995
03996 if (hReye == -1)
03997 {
03998 return;
03999 }
04000
04001 if (!bWink)
04002 {
04003 trap_G2API_SetBoneAngles( cent->ghoul2, 0, "reye", desiredAngles,
04004 BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL, blendTime, cg.time );
04005 }
04006 }
04007
04008
04009
04010
04011
04012
04013 static void CG_G2SetHeadAnim( centity_t *cent, int anim )
04014 {
04015 const int blendTime = 50;
04016 const animation_t *animations = bgAllAnims[cent->localAnimIndex].anims;
04017 int animFlags = BONE_ANIM_OVERRIDE ;
04018
04019
04020 const float timeScaleMod = (cg_timescale.value)?(1.0/cg_timescale.value):1.0;
04021 float animSpeed = 50.0f / animations[anim].frameLerp * timeScaleMod;
04022 int firstFrame;
04023 int lastFrame;
04024
04025 if (animations[anim].numFrames <= 0)
04026 {
04027 return;
04028 }
04029 if (anim == FACE_DEAD)
04030 {
04031 animFlags |= BONE_ANIM_OVERRIDE_FREEZE;
04032 }
04033
04034 if ( animSpeed < 0 )
04035 {
04036
04037 lastFrame = animations[anim].firstFrame -1;
04038 firstFrame = (animations[anim].numFrames -1) + animations[anim].firstFrame ;
04039 }
04040 else
04041 {
04042 firstFrame = animations[anim].firstFrame;
04043 lastFrame = (animations[anim].numFrames) + animations[anim].firstFrame;
04044 }
04045
04046
04047
04048
04049
04050
04051 {
04052
04053
04054 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "face", firstFrame, lastFrame, animFlags, animSpeed,
04055 cg.time, -1, blendTime);
04056 }
04057 }
04058
04059 qboolean CG_G2PlayerHeadAnims( centity_t *cent )
04060 {
04061 clientInfo_t *ci = NULL;
04062 int anim = -1;
04063 int voiceVolume = 0;
04064
04065 if(cent->localAnimIndex > 1)
04066 {
04067 return qfalse;
04068 }
04069
04070 if (cent->noFace)
04071 {
04072 return qfalse;
04073 }
04074
04075 if (cent->currentState.number < MAX_CLIENTS)
04076 {
04077 ci = &cgs.clientinfo[cent->currentState.number];
04078 }
04079 else
04080 {
04081 ci = cent->npcClient;
04082 }
04083
04084 if (!ci)
04085 {
04086 return qfalse;
04087 }
04088
04089 if ( cent->currentState.eFlags & EF_DEAD )
04090 {
04091 anim = FACE_DEAD;
04092 ci->facial_blink = -1;
04093 }
04094 else
04095 {
04096 if (!ci->facial_blink)
04097 {
04098 ci->facial_blink = cg.time + flrand(4000.0, 8000.0);
04099 ci->facial_frown = cg.time + flrand(6000.0, 10000.0);
04100 ci->facial_aux = cg.time + flrand(6000.0, 10000.0);
04101 }
04102
04103
04104 if (ci->facial_blink < 0)
04105 {
04106 if (-(ci->facial_blink) < cg.time)
04107 {
04108 ci->facial_blink = cg.time + flrand(4000.0, 8000.0);
04109 CG_G2SetHeadBlink( cent, qfalse );
04110 }
04111 }
04112 else
04113 {
04114 if (ci->facial_blink < cg.time)
04115 {
04116 CG_G2SetHeadBlink( cent, qtrue );
04117 if (ci->facial_blink == 1)
04118 {
04119 ci->facial_blink = -(cg.time + 99999999.0f);
04120 }
04121 else
04122 {
04123 ci->facial_blink = -(cg.time + 300.0f);
04124 }
04125 }
04126 }
04127
04128 voiceVolume = trap_S_GetVoiceVolume(cent->currentState.number);
04129
04130 if (voiceVolume > 0)
04131 {
04132 anim = FACE_TALK1 + voiceVolume -1;
04133 }
04134 else if (voiceVolume == 0)
04135 {
04136 if (ci->facial_aux < 0)
04137 {
04138 if (-(ci->facial_aux) < cg.time)
04139 {
04140 ci->facial_aux = cg.time + flrand(7000.0, 10000.0);
04141 }
04142 else
04143 {
04144 anim = FACE_ALERT;
04145 }
04146 }
04147 else
04148 {
04149 if (ci->facial_aux < cg.time)
04150 {
04151 anim = FACE_ALERT;
04152
04153 ci->facial_aux = -(cg.time + 2000.0);
04154 }
04155 }
04156
04157 if (anim != -1)
04158 {
04159 if (ci->facial_frown < 0)
04160 {
04161 if (-(ci->facial_frown) < cg.time)
04162 {
04163 ci->facial_frown = cg.time + flrand(7000.0, 10000.0);
04164 }
04165 else
04166 {
04167 anim = FACE_FROWN;
04168 }
04169 }
04170 else
04171 {
04172 if (ci->facial_frown < cg.time)
04173 {
04174 anim = FACE_FROWN;
04175
04176 ci->facial_frown = -(cg.time + 2000.0);
04177 }
04178 }
04179 }
04180
04181 }
04182 }
04183 if (anim != -1)
04184 {
04185 CG_G2SetHeadAnim( cent, anim );
04186 return qtrue;
04187 }
04188 return qfalse;
04189 }
04190
04191
04192 static void CG_G2PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t legsAngles)
04193 {
04194 clientInfo_t *ci;
04195
04196
04197 if ((cent->currentState.eFlags & EF_DEAD) || (cent->currentState.eFlags & EF_RAG))
04198 {
04199 vec3_t forcedAngles;
04200
04201 VectorClear(forcedAngles);
04202 forcedAngles[YAW] = cent->lerpAngles[YAW];
04203
04204 if (CG_RagDoll(cent, forcedAngles))
04205 {
04206 AnglesToAxis( forcedAngles, legs );
04207 VectorCopy(forcedAngles, legsAngles);
04208 return;
04209 }
04210 }
04211 else if (cent->isRagging)
04212 {
04213 cent->isRagging = qfalse;
04214 trap_G2API_SetRagDoll(cent->ghoul2, NULL);
04215 }
04216
04217 if (cent->currentState.eType == ET_NPC)
04218 {
04219 ci = cent->npcClient;
04220 assert(ci);
04221 }
04222 else
04223 {
04224 ci = &cgs.clientinfo[cent->currentState.number];
04225 }
04226
04227
04228 if (cent->localAnimIndex <= 1)
04229 {
04230 vec3_t lookAngles;
04231 entityState_t *emplaced = NULL;
04232
04233 if (cent->currentState.hasLookTarget)
04234 {
04235 VectorSubtract(cg_entities[cent->currentState.lookTarget].lerpOrigin, cent->lerpOrigin, lookAngles);
04236 vectoangles(lookAngles, lookAngles);
04237 ci->lookTime = cg.time + 1000;
04238 }
04239 else
04240 {
04241 VectorCopy(cent->lerpAngles, lookAngles);
04242 }
04243 lookAngles[PITCH] = 0;
04244
04245 if (cent->currentState.otherEntityNum2)
04246 {
04247 emplaced = &cg_entities[cent->currentState.otherEntityNum2].currentState;
04248 }
04249
04250 BG_G2PlayerAngles(cent->ghoul2, ci->bolt_motion, ¢->currentState, cg.time,
04251 cent->lerpOrigin, cent->lerpAngles, legs, legsAngles, ¢->pe.torso.yawing, ¢->pe.torso.pitching,
04252 ¢->pe.legs.yawing, ¢->pe.torso.yawAngle, ¢->pe.torso.pitchAngle, ¢->pe.legs.yawAngle,
04253 cg.frametime, cent->turAngles, cent->modelScale, ci->legsAnim, ci->torsoAnim, &ci->corrTime,
04254 lookAngles, ci->lastHeadAngles, ci->lookTime, emplaced, &ci->superSmoothTime);
04255
04256 if (cent->currentState.heldByClient && cent->currentState.heldByClient <= MAX_CLIENTS)
04257 {
04258
04259 int heldByIndex = cent->currentState.heldByClient-1;
04260 centity_t *other = &cg_entities[heldByIndex];
04261
04262 if (other && other->ghoul2 && ci->bolt_lhand)
04263 {
04264 mdxaBone_t boltMatrix;
04265 vec3_t boltOrg;
04266
04267 trap_G2API_GetBoltMatrix(other->ghoul2, 0, ci->bolt_lhand, &boltMatrix, other->turAngles, other->lerpOrigin, cg.time, cgs.gameModels, other->modelScale);
04268 BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, boltOrg);
04269
04270 BG_IK_MoveArm(cent->ghoul2, ci->bolt_lhand, cg.time, ¢->currentState,
04271 cent->currentState.torsoAnim, boltOrg, ¢->ikStatus, cent->lerpOrigin, cent->lerpAngles, cent->modelScale, 500, qfalse);
04272 }
04273 }
04274 else if (cent->ikStatus)
04275 {
04276 BG_IK_MoveArm(cent->ghoul2, ci->bolt_lhand, cg.time, ¢->currentState,
04277 cent->currentState.torsoAnim, vec3_origin, ¢->ikStatus, cent->lerpOrigin, cent->lerpAngles, cent->modelScale, 500, qtrue);
04278 }
04279 }
04280 else if ( cent->m_pVehicle && cent->m_pVehicle->m_pVehicleInfo->type == VH_WALKER )
04281 {
04282 vec3_t lookAngles;
04283
04284 VectorCopy(cent->lerpAngles, legsAngles);
04285 legsAngles[PITCH] = 0;
04286 AnglesToAxis( legsAngles, legs );
04287
04288 VectorCopy(cent->lerpAngles, lookAngles);
04289 lookAngles[YAW] = lookAngles[ROLL] = 0;
04290
04291 BG_G2ATSTAngles( cent->ghoul2, cg.time, lookAngles );
04292 }
04293 else
04294 {
04295 if (cent->currentState.eType == ET_NPC &&
04296 cent->currentState.NPC_class == CLASS_VEHICLE &&
04297 cent->m_pVehicle &&
04298 cent->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER)
04299 {
04300 VectorCopy(cent->lerpAngles, legsAngles);
04301 AnglesToAxis( legsAngles, legs );
04302 }
04303 else if (cent->currentState.eType == ET_NPC &&
04304 cent->currentState.m_iVehicleNum &&
04305 cent->currentState.NPC_class != CLASS_VEHICLE )
04306 {
04307 VectorCopy(cent->lerpAngles, legsAngles);
04308 AnglesToAxis( legsAngles, legs );
04309 }
04310 else
04311 {
04312 vec3_t nhAngles;
04313
04314 if (cent->currentState.eType == ET_NPC &&
04315 cent->currentState.NPC_class == CLASS_VEHICLE &&
04316 cent->m_pVehicle &&
04317 cent->m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER)
04318 {
04319 VectorSet(nhAngles, 0, cent->lerpAngles[YAW], cent->lerpAngles[ROLL]);
04320 }
04321 else
04322 {
04323 VectorSet(nhAngles, 0, cent->lerpAngles[YAW], 0);
04324 }
04325 AnglesToAxis( nhAngles, legs );
04326 }
04327 }
04328
04329
04330 CG_G2ServerBoneAngles(cent);
04331 }
04332
04333
04334
04335
04336
04337
04338
04339 #if 0
04340 static void CG_TrailItem( centity_t *cent, qhandle_t hModel ) {
04341 refEntity_t ent;
04342 vec3_t angles;
04343 vec3_t axis[3];
04344
04345 VectorCopy( cent->lerpAngles, angles );
04346 angles[PITCH] = 0;
04347 angles[ROLL] = 0;
04348 AnglesToAxis( angles, axis );
04349
04350 memset( &ent, 0, sizeof( ent ) );
04351 VectorMA( cent->lerpOrigin, -16, axis[0], ent.origin );
04352 ent.origin[2] += 16;
04353 angles[YAW] += 90;
04354 AnglesToAxis( angles, ent.axis );
04355
04356 ent.hModel = hModel;
04357 trap_R_AddRefEntityToScene( &ent );
04358 }
04359 #endif
04360
04361
04362
04363
04364
04365
04366
04367 static void CG_PlayerFlag( centity_t *cent, qhandle_t hModel ) {
04368 refEntity_t ent;
04369 vec3_t angles;
04370 vec3_t axis[3];
04371 vec3_t boltOrg, tAng, getAng, right;
04372 mdxaBone_t boltMatrix;
04373 clientInfo_t *ci;
04374
04375 if (cent->currentState.number == cg.snap->ps.clientNum &&
04376 !cg.renderingThirdPerson)
04377 {
04378 return;
04379 }
04380
04381 if (!cent->ghoul2)
04382 {
04383 return;
04384 }
04385
04386 if (cent->currentState.eType == ET_NPC)
04387 {
04388 ci = cent->npcClient;
04389 assert(ci);
04390 }
04391 else
04392 {
04393 ci = &cgs.clientinfo[cent->currentState.number];
04394 }
04395
04396 VectorSet( tAng, cent->turAngles[PITCH], cent->turAngles[YAW], cent->turAngles[ROLL] );
04397
04398 trap_G2API_GetBoltMatrix(cent->ghoul2, 0, ci->bolt_llumbar, &boltMatrix, tAng, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale);
04399 BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, boltOrg);
04400
04401 BG_GiveMeVectorFromMatrix(&boltMatrix, POSITIVE_X, tAng);
04402 vectoangles(tAng, tAng);
04403
04404 VectorCopy(cent->lerpAngles, angles);
04405
04406 boltOrg[2] -= 12;
04407 VectorSet(getAng, 0, cent->lerpAngles[1], 0);
04408 AngleVectors(getAng, 0, right, 0);
04409 boltOrg[0] += right[0]*8;
04410 boltOrg[1] += right[1]*8;
04411 boltOrg[2] += right[2]*8;
04412
04413 angles[PITCH] = -cent->lerpAngles[PITCH]/2-30;
04414 angles[YAW] = tAng[YAW]+270;
04415
04416 AnglesToAxis(angles, axis);
04417
04418 memset( &ent, 0, sizeof( ent ) );
04419 VectorMA( boltOrg, 24, axis[0], ent.origin );
04420
04421 angles[ROLL] += 20;
04422 AnglesToAxis( angles, ent.axis );
04423
04424 ent.hModel = hModel;
04425
04426 ent.modelScale[0] = 0.5;
04427 ent.modelScale[1] = 0.5;
04428 ent.modelScale[2] = 0.5;
04429 ScaleModelAxis(&ent);
04430
04431
04432
04433
04434
04435
04436
04437
04438
04439
04440 trap_R_AddRefEntityToScene( &ent );
04441 }
04442
04443
04444
04445
04446
04447
04448
04449 static void CG_PlayerPowerups( centity_t *cent, refEntity_t *torso ) {
04450 int powerups;
04451 clientInfo_t *ci;
04452
04453 powerups = cent->currentState.powerups;
04454 if ( !powerups ) {
04455 return;
04456 }
04457
04458
04459 if ( powerups & ( 1 << PW_QUAD ) ) {
04460 trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2f, 0.2f, 1 );
04461 }
04462
04463 if (cent->currentState.eType == ET_NPC)
04464 {
04465 ci = cent->npcClient;
04466 assert(ci);
04467 }
04468 else
04469 {
04470 ci = &cgs.clientinfo[ cent->currentState.clientNum ];
04471 }
04472
04473 if ( powerups & ( 1 << PW_REDFLAG ) ) {
04474 CG_PlayerFlag( cent, cgs.media.redFlagModel );
04475 trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1.0, 0.2f, 0.2f );
04476 }
04477
04478
04479 if ( powerups & ( 1 << PW_BLUEFLAG ) ) {
04480 CG_PlayerFlag( cent, cgs.media.blueFlagModel );
04481 trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 0.2f, 0.2f, 1.0 );
04482 }
04483
04484
04485 if ( powerups & ( 1 << PW_NEUTRALFLAG ) ) {
04486 trap_R_AddLightToScene( cent->lerpOrigin, 200 + (rand()&31), 1.0, 1.0, 1.0 );
04487 }
04488
04489
04490
04491
04492
04493
04494
04495 }
04496
04497
04498
04499
04500
04501
04502
04503
04504
04505 static void CG_PlayerFloatSprite( centity_t *cent, qhandle_t shader ) {
04506 int rf;
04507 refEntity_t ent;
04508
04509 if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson ) {
04510 rf = RF_THIRD_PERSON;
04511 } else {
04512 rf = 0;
04513 }
04514
04515 memset( &ent, 0, sizeof( ent ) );
04516 VectorCopy( cent->lerpOrigin, ent.origin );
04517 ent.origin[2] += 48;
04518 ent.reType = RT_SPRITE;
04519 ent.customShader = shader;
04520 ent.radius = 10;
04521 ent.renderfx = rf;
04522 ent.shaderRGBA[0] = 255;
04523 ent.shaderRGBA[1] = 255;
04524 ent.shaderRGBA[2] = 255;
04525 ent.shaderRGBA[3] = 255;
04526 trap_R_AddRefEntityToScene( &ent );
04527 }
04528
04529
04530
04531
04532
04533
04534
04535
04536
04537
04538 #if 0
04539 static void CG_PlayerFloatSpriteRGBA( centity_t *cent, qhandle_t shader, vec4_t rgba ) {
04540 int rf;
04541 refEntity_t ent;
04542
04543 if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson ) {
04544 rf = RF_THIRD_PERSON;
04545 } else {
04546 rf = 0;
04547 }
04548
04549 memset( &ent, 0, sizeof( ent ) );
04550 VectorCopy( cent->lerpOrigin, ent.origin );
04551 ent.origin[2] += 48;
04552 ent.reType = RT_SPRITE;
04553 ent.customShader = shader;
04554 ent.radius = 10;
04555 ent.renderfx = rf;
04556 ent.shaderRGBA[0] = rgba[0];
04557 ent.shaderRGBA[1] = rgba[1];
04558 ent.shaderRGBA[2] = rgba[2];
04559 ent.shaderRGBA[3] = rgba[3];
04560 trap_R_AddRefEntityToScene( &ent );
04561 }
04562 #endif
04563
04564
04565
04566
04567
04568
04569
04570
04571
04572 static void CG_PlayerSprites( centity_t *cent ) {
04573
04574
04575 if (cg.snap &&
04576 CG_IsMindTricked(cent->currentState.trickedentindex,
04577 cent->currentState.trickedentindex2,
04578 cent->currentState.trickedentindex3,
04579 cent->currentState.trickedentindex4,
04580 cg.snap->ps.clientNum))
04581 {
04582 return;
04583 }
04584
04585 if ( cent->currentState.eFlags & EF_CONNECTION ) {
04586 CG_PlayerFloatSprite( cent, cgs.media.connectionShader );
04587 return;
04588 }
04589
04590 if (cent->vChatTime > cg.time)
04591 {
04592 CG_PlayerFloatSprite( cent, cgs.media.vchatShader );
04593 }
04594 else if ( cent->currentState.eType != ET_NPC &&
04595 (cent->currentState.eFlags & EF_TALK) )
04596 {
04597 CG_PlayerFloatSprite( cent, cgs.media.balloonShader );
04598 return;
04599 }
04600 }
04601
04602
04603
04604
04605
04606
04607
04608
04609
04610
04611 #define SHADOW_DISTANCE 128
04612 static qboolean CG_PlayerShadow( centity_t *cent, float *shadowPlane ) {
04613 vec3_t end, mins = {-15, -15, 0}, maxs = {15, 15, 2};
04614 trace_t trace;
04615 float alpha;
04616 float radius = 24.0f;
04617
04618 *shadowPlane = 0;
04619
04620 if ( cg_shadows.integer == 0 ) {
04621 return qfalse;
04622 }
04623
04624
04625 if ( cent->currentState.powerups & ( 1 << PW_CLOAKED ))
04626 {
04627 return qfalse;
04628 }
04629
04630 if (cent->currentState.eFlags & EF_DEAD)
04631 {
04632 return qfalse;
04633 }
04634
04635 if (CG_IsMindTricked(cent->currentState.trickedentindex,
04636 cent->currentState.trickedentindex2,
04637 cent->currentState.trickedentindex3,
04638 cent->currentState.trickedentindex4,
04639 cg.snap->ps.clientNum))
04640 {
04641 return qfalse;
04642 }
04643
04644 if ( cg_shadows.integer == 1 )
04645 {
04646 if (cent->currentState.m_iVehicleNum &&
04647 cent->currentState.NPC_class != CLASS_VEHICLE )
04648 {
04649 return qfalse;
04650 }
04651 }
04652
04653 VectorCopy( cent->lerpOrigin, end );
04654 if (cg_shadows.integer == 2)
04655 {
04656 end[2] -= 4096.0f;
04657
04658 trap_CM_BoxTrace( &trace, cent->lerpOrigin, end, mins, maxs, 0, MASK_PLAYERSOLID );
04659
04660 if ( trace.fraction == 1.0 || trace.startsolid || trace.allsolid )
04661 {
04662 trace.endpos[2] = cent->lerpOrigin[2]-25.0f;
04663 }
04664 }
04665 else
04666 {
04667 end[2] -= SHADOW_DISTANCE;
04668
04669 trap_CM_BoxTrace( &trace, cent->lerpOrigin, end, mins, maxs, 0, MASK_PLAYERSOLID );
04670
04671
04672 if ( trace.fraction == 1.0 || trace.startsolid || trace.allsolid ) {
04673 return qfalse;
04674 }
04675 }
04676
04677 if (cg_shadows.integer == 2)
04678 {
04679 *shadowPlane = trace.endpos[2];
04680 }
04681 else
04682 {
04683 *shadowPlane = trace.endpos[2] + 1;
04684 }
04685
04686 if ( cg_shadows.integer != 1 ) {
04687 return qtrue;
04688 }
04689
04690
04691 alpha = 1.0 - trace.fraction;
04692
04693
04694
04695
04696
04697
04698 if ( cent->currentState.NPC_class == CLASS_REMOTE
04699 || cent->currentState.NPC_class == CLASS_SEEKER )
04700 {
04701 radius = 8.0f;
04702 }
04703 CG_ImpactMark( cgs.media.shadowMarkShader, trace.endpos, trace.plane.normal,
04704 cent->pe.legs.yawAngle, alpha,alpha,alpha,1, qfalse, radius, qtrue );
04705
04706 return qtrue;
04707 }
04708
04709
04710
04711
04712
04713
04714
04715
04716
04717 static void CG_PlayerSplash( centity_t *cent ) {
04718 vec3_t start, end;
04719 trace_t trace;
04720 int contents;
04721 polyVert_t verts[4];
04722
04723 if ( !cg_shadows.integer ) {
04724 return;
04725 }
04726
04727 VectorCopy( cent->lerpOrigin, end );
04728 end[2] -= 24;
04729
04730
04731
04732 contents = trap_CM_PointContents( end, 0 );
04733 if ( !( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) ) {
04734 return;
04735 }
04736
04737 VectorCopy( cent->lerpOrigin, start );
04738 start[2] += 32;
04739
04740
04741 contents = trap_CM_PointContents( start, 0 );
04742 if ( contents & ( CONTENTS_SOLID | CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
04743 return;
04744 }
04745
04746
04747 trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) );
04748
04749 if ( trace.fraction == 1.0 ) {
04750 return;
04751 }
04752
04753
04754 VectorCopy( trace.endpos, verts[0].xyz );
04755 verts[0].xyz[0] -= 32;
04756 verts[0].xyz[1] -= 32;
04757 verts[0].st[0] = 0;
04758 verts[0].st[1] = 0;
04759 verts[0].modulate[0] = 255;
04760 verts[0].modulate[1] = 255;
04761 verts[0].modulate[2] = 255;
04762 verts[0].modulate[3] = 255;
04763
04764 VectorCopy( trace.endpos, verts[1].xyz );
04765 verts[1].xyz[0] -= 32;
04766 verts[1].xyz[1] += 32;
04767 verts[1].st[0] = 0;
04768 verts[1].st[1] = 1;
04769 verts[1].modulate[0] = 255;
04770 verts[1].modulate[1] = 255;
04771 verts[1].modulate[2] = 255;
04772 verts[1].modulate[3] = 255;
04773
04774 VectorCopy( trace.endpos, verts[2].xyz );
04775 verts[2].xyz[0] += 32;
04776 verts[2].xyz[1] += 32;
04777 verts[2].st[0] = 1;
04778 verts[2].st[1] = 1;
04779 verts[2].modulate[0] = 255;
04780 verts[2].modulate[1] = 255;
04781 verts[2].modulate[2] = 255;
04782 verts[2].modulate[3] = 255;
04783
04784 VectorCopy( trace.endpos, verts[3].xyz );
04785 verts[3].xyz[0] += 32;
04786 verts[3].xyz[1] -= 32;
04787 verts[3].st[0] = 1;
04788 verts[3].st[1] = 0;
04789 verts[3].modulate[0] = 255;
04790 verts[3].modulate[1] = 255;
04791 verts[3].modulate[2] = 255;
04792 verts[3].modulate[3] = 255;
04793
04794 trap_R_AddPolyToScene( cgs.media.wakeMarkShader, 4, verts );
04795 }
04796
04797 #define REFRACT_EFFECT_DURATION 500
04798 static void CG_ForcePushBlur( vec3_t org, centity_t *cent )
04799 {
04800 if (!cent || !cg_renderToTextureFX.integer)
04801 {
04802 localEntity_t *ex;
04803
04804 ex = CG_AllocLocalEntity();
04805 ex->leType = LE_PUFF;
04806 ex->refEntity.reType = RT_SPRITE;
04807 ex->radius = 2.0f;
04808 ex->startTime = cg.time;
04809 ex->endTime = ex->startTime + 120;
04810 VectorCopy( org, ex->pos.trBase );
04811 ex->pos.trTime = cg.time;
04812 ex->pos.trType = TR_LINEAR;
04813 VectorScale( cg.refdef.viewaxis[1], 55, ex->pos.trDelta );
04814
04815 ex->color[0] = 24;
04816 ex->color[1] = 32;
04817 ex->color[2] = 40;
04818 ex->refEntity.customShader = trap_R_RegisterShader( "gfx/effects/forcePush" );
04819
04820 ex = CG_AllocLocalEntity();
04821 ex->leType = LE_PUFF;
04822 ex->refEntity.reType = RT_SPRITE;
04823 ex->refEntity.rotation = 180.0f;
04824 ex->radius = 2.0f;
04825 ex->startTime = cg.time;
04826 ex->endTime = ex->startTime + 120;
04827 VectorCopy( org, ex->pos.trBase );
04828 ex->pos.trTime = cg.time;
04829 ex->pos.trType = TR_LINEAR;
04830 VectorScale( cg.refdef.viewaxis[1], -55, ex->pos.trDelta );
04831
04832 ex->color[0] = 24;
04833 ex->color[1] = 32;
04834 ex->color[2] = 40;
04835 ex->refEntity.customShader = trap_R_RegisterShader( "gfx/effects/forcePush" );
04836 }
04837 else
04838 {
04839 refEntity_t ent;
04840 vec3_t ang;
04841 float scale;
04842 float vLen;
04843 float alpha;
04844 int tDif;
04845
04846 if (!cent->bodyFadeTime)
04847 {
04848 cent->bodyFadeTime = cg.time + REFRACT_EFFECT_DURATION;
04849 }
04850
04851
04852
04853 tDif = (cent->bodyFadeTime - cg.time);
04854
04855 if ((REFRACT_EFFECT_DURATION-tDif) < 200)
04856 {
04857
04858 VectorCopy(org, cent->pushEffectOrigin);
04859 }
04860
04861
04862 if (cent->currentState.powerups & (1 << PW_PULL))
04863 {
04864 scale = (float)(REFRACT_EFFECT_DURATION-tDif)*0.003f;
04865 }
04866 else
04867 {
04868 scale = (float)(tDif)*0.003f;
04869 }
04870
04871 if (scale > 1.0f)
04872 {
04873 scale = 1.0f;
04874 }
04875 else if (scale < 0.2f)
04876 {
04877 scale = 0.2f;
04878 }
04879
04880
04881 alpha = (float)tDif*0.488f;
04882
04883 if (alpha > 244.0f)
04884 {
04885 alpha = 244.0f;
04886 }
04887 else if (alpha < 10.0f)
04888 {
04889 alpha = 10.0f;
04890 }
04891
04892 memset( &ent, 0, sizeof( ent ) );
04893 ent.shaderTime = (cent->bodyFadeTime-REFRACT_EFFECT_DURATION) / 1000.0f;
04894
04895 VectorCopy( cent->pushEffectOrigin, ent.origin );
04896
04897 VectorSubtract(ent.origin, cg.refdef.vieworg, ent.axis[0]);
04898 vLen = VectorLength(ent.axis[0]);
04899 if (vLen <= 0.1f)
04900 {
04901 return;
04902 }
04903
04904 vectoangles(ent.axis[0], ang);
04905 ang[ROLL] += 180.0f;
04906 AnglesToAxis(ang, ent.axis);
04907
04908
04909 if (vLen < 128)
04910 {
04911 ent.radius = 256;
04912 }
04913 else if (vLen < 256)
04914 {
04915 ent.radius = 128;
04916 }
04917 else if (vLen < 512)
04918 {
04919 ent.radius = 64;
04920 }
04921 else
04922 {
04923 ent.radius = 32;
04924 }
04925
04926 VectorScale(ent.axis[0], scale, ent.axis[0]);
04927 VectorScale(ent.axis[1], scale, ent.axis[1]);
04928 VectorScale(ent.axis[2], scale, ent.axis[2]);
04929
04930 ent.hModel = cgs.media.halfShieldModel;
04931 ent.customShader = cgs.media.refractionShader;
04932 ent.nonNormalizedAxes = qtrue;
04933
04934
04935 ent.renderfx = (RF_DISTORTION|RF_FORCE_ENT_ALPHA);
04936 ent.shaderRGBA[0] = 255.0f;
04937 ent.shaderRGBA[1] = 255.0f;
04938 ent.shaderRGBA[2] = 255.0f;
04939 ent.shaderRGBA[3] = alpha;
04940
04941 trap_R_AddRefEntityToScene( &ent );
04942 }
04943 }
04944
04945 static const char *cg_pushBoneNames[] =
04946 {
04947 "cranium",
04948 "lower_lumbar",
04949 "rhand",
04950 "lhand",
04951 "ltibia",
04952 "rtibia",
04953 "lradius",
04954 "rradius",
04955 NULL
04956 };
04957
04958 static void CG_ForcePushBodyBlur( centity_t *cent )
04959 {
04960 vec3_t fxOrg;
04961 mdxaBone_t boltMatrix;
04962 int bolt;
04963 int i;
04964
04965 if (cent->localAnimIndex > 1)
04966 {
04967 return;
04968 }
04969
04970 if (cg.snap &&
04971 CG_IsMindTricked(cent->currentState.trickedentindex,
04972 cent->currentState.trickedentindex2,
04973 cent->currentState.trickedentindex3,
04974 cent->currentState.trickedentindex4,
04975 cg.snap->ps.clientNum))
04976 {
04977 return;
04978 }
04979
04980 assert(cent->ghoul2);
04981
04982 for (i = 0; cg_pushBoneNames[i]; i++)
04983 {
04984 bolt = trap_G2API_AddBolt(cent->ghoul2, 0, cg_pushBoneNames[i]);
04985
04986 if (bolt == -1)
04987 {
04988 assert(!"You've got an invalid bone/bolt name in cg_pushBoneNames");
04989 continue;
04990 }
04991
04992 trap_G2API_GetBoltMatrix(cent->ghoul2, 0, bolt, &boltMatrix, cent->turAngles, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale);
04993 BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, fxOrg);
04994
04995
04996 CG_ForcePushBlur(fxOrg, NULL);
04997 }
04998 }
04999
05000 static void CG_ForceGripEffect( vec3_t org )
05001 {
05002 localEntity_t *ex;
05003 float wv = sin( cg.time * 0.004f ) * 0.08f + 0.1f;
05004
05005 ex = CG_AllocLocalEntity();
05006 ex->leType = LE_PUFF;
05007 ex->refEntity.reType = RT_SPRITE;
05008 ex->radius = 2.0f;
05009 ex->startTime = cg.time;
05010 ex->endTime = ex->startTime + 120;
05011 VectorCopy( org, ex->pos.trBase );
05012 ex->pos.trTime = cg.time;
05013 ex->pos.trType = TR_LINEAR;
05014 VectorScale( cg.refdef.viewaxis[1], 55, ex->pos.trDelta );
05015
05016 ex->color[0] = 200+((wv*255));
05017 if (ex->color[0] > 255)
05018 {
05019 ex->color[0] = 255;
05020 }
05021 ex->color[1] = 0;
05022 ex->color[2] = 0;
05023 ex->refEntity.customShader = trap_R_RegisterShader( "gfx/effects/forcePush" );
05024
05025 ex = CG_AllocLocalEntity();
05026 ex->leType = LE_PUFF;
05027 ex->refEntity.reType = RT_SPRITE;
05028 ex->refEntity.rotation = 180.0f;
05029 ex->radius = 2.0f;
05030 ex->startTime = cg.time;
05031 ex->endTime = ex->startTime + 120;
05032 VectorCopy( org, ex->pos.trBase );
05033 ex->pos.trTime = cg.time;
05034 ex->pos.trType = TR_LINEAR;
05035 VectorScale( cg.refdef.viewaxis[1], -55, ex->pos.trDelta );
05036
05037
05038
05039
05040
05041
05042
05043
05044 ex->color[0] = 255;
05045 ex->color[1] = 255;
05046 ex->color[2] = 255;
05047 ex->refEntity.customShader = cgs.media.redSaberGlowShader;
05048 }
05049
05050
05051
05052
05053
05054
05055
05056
05057
05058
05059 void CG_AddRefEntityWithPowerups( refEntity_t *ent, entityState_t *state, int team ) {
05060
05061 if (CG_IsMindTricked(state->trickede