codemp/cgame/cg_weapons.c

Go to the documentation of this file.
00001 // Copyright (C) 1999-2000 Id Software, Inc.
00002 //
00003 // cg_weapons.c -- events and effects dealing with weapons
00004 #include "cg_local.h"
00005 #include "fx_local.h"
00006 
00007 extern vec4_t   bluehudtint;
00008 extern vec4_t   redhudtint;
00009 extern float    *hudTintColor;
00010 
00011 /*
00012 Ghoul2 Insert Start
00013 */
00014 // set up the appropriate ghoul2 info to a refent
00015 void CG_SetGhoul2InfoRef( refEntity_t *ent, refEntity_t *s1)
00016 {
00017         ent->ghoul2 = s1->ghoul2;
00018         VectorCopy( s1->modelScale, ent->modelScale);
00019         ent->radius = s1->radius;
00020         VectorCopy( s1->angles, ent->angles);
00021 }
00022 
00023 /*
00024 Ghoul2 Insert End
00025 */
00026 
00027 /*
00028 =================
00029 CG_RegisterItemVisuals
00030 
00031 The server says this item is used on this level
00032 =================
00033 */
00034 void CG_RegisterItemVisuals( int itemNum ) {
00035         itemInfo_t              *itemInfo;
00036         gitem_t                 *item;
00037         int                             handle;
00038 
00039         if ( itemNum < 0 || itemNum >= bg_numItems ) {
00040                 CG_Error( "CG_RegisterItemVisuals: itemNum %d out of range [0-%d]", itemNum, bg_numItems-1 );
00041         }
00042 
00043         itemInfo = &cg_items[ itemNum ];
00044         if ( itemInfo->registered ) {
00045                 return;
00046         }
00047 
00048         item = &bg_itemlist[ itemNum ];
00049 
00050         memset( itemInfo, 0, sizeof( &itemInfo ) );
00051         itemInfo->registered = qtrue;
00052 
00053         if (item->giType == IT_TEAM &&
00054                 (item->giTag == PW_REDFLAG || item->giTag == PW_BLUEFLAG) &&
00055                 cgs.gametype == GT_CTY)
00056         { //in CTY the flag model is different
00057                 itemInfo->models[0] = trap_R_RegisterModel( item->world_model[1] );
00058         }
00059         else if (item->giType == IT_WEAPON &&
00060                 (item->giTag == WP_THERMAL || item->giTag == WP_TRIP_MINE || item->giTag == WP_DET_PACK))
00061         {
00062                 itemInfo->models[0] = trap_R_RegisterModel( item->world_model[1] );
00063         }
00064         else
00065         {
00066                 itemInfo->models[0] = trap_R_RegisterModel( item->world_model[0] );
00067         }
00068 /*
00069 Ghoul2 Insert Start
00070 */
00071         if (!Q_stricmp(&item->world_model[0][strlen(item->world_model[0]) - 4], ".glm"))
00072         {
00073                 handle = trap_G2API_InitGhoul2Model(&itemInfo->g2Models[0], item->world_model[0], 0 , 0, 0, 0, 0);
00074                 if (handle<0)
00075                 {
00076                         itemInfo->g2Models[0] = NULL;
00077                 }
00078                 else
00079                 {
00080                         itemInfo->radius[0] = 60;
00081                 }
00082         }
00083 /*
00084 Ghoul2 Insert End
00085 */
00086         if (item->icon)
00087         {
00088                 if (item->giType == IT_HEALTH)
00089                 { //medpack gets nomip'd by the ui or something I guess.
00090                         itemInfo->icon = trap_R_RegisterShaderNoMip( item->icon );
00091                 }
00092                 else
00093                 {
00094                         itemInfo->icon = trap_R_RegisterShader( item->icon );
00095                 }
00096         }
00097         else
00098         {
00099                 itemInfo->icon = 0;
00100         }
00101 
00102         if ( item->giType == IT_WEAPON ) {
00103                 CG_RegisterWeapon( item->giTag );
00104         }
00105 
00106         //
00107         // powerups have an accompanying ring or sphere
00108         //
00109         if ( item->giType == IT_POWERUP || item->giType == IT_HEALTH || 
00110                 item->giType == IT_ARMOR || item->giType == IT_HOLDABLE ) {
00111                 if ( item->world_model[1] ) {
00112                         itemInfo->models[1] = trap_R_RegisterModel( item->world_model[1] );
00113                 }
00114         }
00115 }
00116 
00117 
00118 /*
00119 ========================================================================================
00120 
00121 VIEW WEAPON
00122 
00123 ========================================================================================
00124 */
00125 
00126 #define WEAPON_FORCE_BUSY_HOLSTER
00127 
00128 #ifdef WEAPON_FORCE_BUSY_HOLSTER
00129 //rww - this was done as a last resort. Forgive me.
00130 static int cgWeapFrame = 0;
00131 static int cgWeapFrameTime = 0;
00132 #endif
00133 
00134 /*
00135 =================
00136 CG_MapTorsoToWeaponFrame
00137 
00138 =================
00139 */
00140 static int CG_MapTorsoToWeaponFrame( clientInfo_t *ci, int frame, int animNum ) {
00141         animation_t *animations = bgHumanoidAnimations;
00142 #ifdef WEAPON_FORCE_BUSY_HOLSTER
00143         if (cg.snap->ps.forceHandExtend != HANDEXTEND_NONE || cgWeapFrameTime > cg.time)
00144         { //the reason for the after delay is so that it doesn't snap the weapon frame to the "idle" (0) frame
00145                 //for a very quick moment
00146                 if (cgWeapFrame < 6)
00147                 {
00148                         cgWeapFrame = 6;
00149                         cgWeapFrameTime = cg.time + 10;
00150                 }
00151 
00152                 if (cgWeapFrameTime < cg.time && cgWeapFrame < 10)
00153                 {
00154                         cgWeapFrame++;
00155                         cgWeapFrameTime = cg.time + 10;
00156                 }
00157 
00158                 if (cg.snap->ps.forceHandExtend != HANDEXTEND_NONE &&
00159                         cgWeapFrame == 10)
00160                 {
00161                         cgWeapFrameTime = cg.time + 100;
00162                 }
00163 
00164                 return cgWeapFrame;
00165         }
00166         else
00167         {
00168                 cgWeapFrame = 0;
00169                 cgWeapFrameTime = 0;
00170         }
00171 #endif
00172 
00173         switch( animNum )
00174         {
00175         case TORSO_DROPWEAP1:
00176                 if ( frame >= animations[animNum].firstFrame && frame < animations[animNum].firstFrame + 5 ) 
00177                 {
00178                         return frame - animations[animNum].firstFrame + 6;
00179                 }
00180                 break;
00181 
00182         case TORSO_RAISEWEAP1:
00183                 if ( frame >= animations[animNum].firstFrame && frame < animations[animNum].firstFrame + 4 ) 
00184                 {
00185                         return frame - animations[animNum].firstFrame + 6 + 4;
00186                 }
00187                 break;
00188         case BOTH_ATTACK1:
00189         case BOTH_ATTACK2:
00190         case BOTH_ATTACK3:
00191         case BOTH_ATTACK4:
00192         case BOTH_ATTACK10:
00193         case BOTH_THERMAL_THROW:
00194                 if ( frame >= animations[animNum].firstFrame && frame < animations[animNum].firstFrame + 6 ) 
00195                 {
00196                         return 1 + ( frame - animations[animNum].firstFrame );
00197                 }
00198 
00199                 break;
00200         }       
00201         return -1;
00202 }
00203 
00204 
00205 /*
00206 ==============
00207 CG_CalculateWeaponPosition
00208 ==============
00209 */
00210 static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles ) {
00211         float   scale;
00212         int             delta;
00213         float   fracsin;
00214 
00215         VectorCopy( cg.refdef.vieworg, origin );
00216         VectorCopy( cg.refdef.viewangles, angles );
00217 
00218         // on odd legs, invert some angles
00219         if ( cg.bobcycle & 1 ) {
00220                 scale = -cg.xyspeed;
00221         } else {
00222                 scale = cg.xyspeed;
00223         }
00224 
00225         // gun angles from bobbing
00226         angles[ROLL] += scale * cg.bobfracsin * 0.005;
00227         angles[YAW] += scale * cg.bobfracsin * 0.01;
00228         angles[PITCH] += cg.xyspeed * cg.bobfracsin * 0.005;
00229 
00230         // drop the weapon when landing
00231         delta = cg.time - cg.landTime;
00232         if ( delta < LAND_DEFLECT_TIME ) {
00233                 origin[2] += cg.landChange*0.25 * delta / LAND_DEFLECT_TIME;
00234         } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
00235                 origin[2] += cg.landChange*0.25 * 
00236                         (LAND_DEFLECT_TIME + LAND_RETURN_TIME - delta) / LAND_RETURN_TIME;
00237         }
00238 
00239 #if 0
00240         // drop the weapon when stair climbing
00241         delta = cg.time - cg.stepTime;
00242         if ( delta < STEP_TIME/2 ) {
00243                 origin[2] -= cg.stepChange*0.25 * delta / (STEP_TIME/2);
00244         } else if ( delta < STEP_TIME ) {
00245                 origin[2] -= cg.stepChange*0.25 * (STEP_TIME - delta) / (STEP_TIME/2);
00246         }
00247 #endif
00248 
00249         // idle drift
00250         scale = cg.xyspeed + 40;
00251         fracsin = sin( cg.time * 0.001 );
00252         angles[ROLL] += scale * fracsin * 0.01;
00253         angles[YAW] += scale * fracsin * 0.01;
00254         angles[PITCH] += scale * fracsin * 0.01;
00255 }
00256 
00257 
00258 /*
00259 ===============
00260 CG_LightningBolt
00261 
00262 Origin will be the exact tag point, which is slightly
00263 different than the muzzle point used for determining hits.
00264 The cent should be the non-predicted cent if it is from the player,
00265 so the endpoint will reflect the simulated strike (lagging the predicted
00266 angle)
00267 ===============
00268 */
00269 static void CG_LightningBolt( centity_t *cent, vec3_t origin ) {
00270 //      trace_t  trace;
00271         refEntity_t  beam;
00272 //      vec3_t   forward;
00273 //      vec3_t   muzzlePoint, endPoint;
00274 
00275         //Must be a durational weapon that continuously generates an effect.
00276         if ( cent->currentState.weapon == WP_DEMP2 && cent->currentState.eFlags & EF_ALT_FIRING ) 
00277         { /*nothing*/ }
00278         else
00279         {
00280                 return;
00281         }
00282 
00283         memset( &beam, 0, sizeof( beam ) );
00284 
00285         // NOTENOTE No lightning gun-ish stuff yet.
00286 /*
00287         // CPMA  "true" lightning
00288         if ((cent->currentState.number == cg.predictedPlayerState.clientNum) && (cg_trueLightning.value != 0)) {
00289                 vec3_t angle;
00290                 int i;
00291 
00292                 for (i = 0; i < 3; i++) {
00293                         float a = cent->lerpAngles[i] - cg.refdef.viewangles[i];
00294                         if (a > 180) {
00295                                 a -= 360;
00296                         }
00297                         if (a < -180) {
00298                                 a += 360;
00299                         }
00300 
00301                         angle[i] = cg.refdef.viewangles[i] + a * (1.0 - cg_trueLightning.value);
00302                         if (angle[i] < 0) {
00303                                 angle[i] += 360;
00304                         }
00305                         if (angle[i] > 360) {
00306                                 angle[i] -= 360;
00307                         }
00308                 }
00309 
00310                 AngleVectors(angle, forward, NULL, NULL );
00311                 VectorCopy(cent->lerpOrigin, muzzlePoint );
00312 //              VectorCopy(cg.refdef.vieworg, muzzlePoint );
00313         } else {
00314                 // !CPMA
00315                 AngleVectors( cent->lerpAngles, forward, NULL, NULL );
00316                 VectorCopy(cent->lerpOrigin, muzzlePoint );
00317         }
00318 
00319         // FIXME: crouch
00320         muzzlePoint[2] += DEFAULT_VIEWHEIGHT;
00321 
00322         VectorMA( muzzlePoint, 14, forward, muzzlePoint );
00323 
00324         // project forward by the lightning range
00325         VectorMA( muzzlePoint, LIGHTNING_RANGE, forward, endPoint );
00326 
00327         // see if it hit a wall
00328         CG_Trace( &trace, muzzlePoint, vec3_origin, vec3_origin, endPoint, 
00329                 cent->currentState.number, MASK_SHOT );
00330 
00331         // this is the endpoint
00332         VectorCopy( trace.endpos, beam.oldorigin );
00333 
00334         // use the provided origin, even though it may be slightly
00335         // different than the muzzle origin
00336         VectorCopy( origin, beam.origin );
00337 
00338         beam.reType = RT_LIGHTNING;
00339         beam.customShader = cgs.media.lightningShader;
00340         trap_R_AddRefEntityToScene( &beam );
00341 */
00342 
00343         // NOTENOTE No lightning gun-ish stuff yet.
00344 /*
00345         // add the impact flare if it hit something
00346         if ( trace.fraction < 1.0 ) {
00347                 vec3_t  angles;
00348                 vec3_t  dir;
00349 
00350                 VectorSubtract( beam.oldorigin, beam.origin, dir );
00351                 VectorNormalize( dir );
00352 
00353                 memset( &beam, 0, sizeof( beam ) );
00354                 beam.hModel = cgs.media.lightningExplosionModel;
00355 
00356                 VectorMA( trace.endpos, -16, dir, beam.origin );
00357 
00358                 // make a random orientation
00359                 angles[0] = rand() % 360;
00360                 angles[1] = rand() % 360;
00361                 angles[2] = rand() % 360;
00362                 AnglesToAxis( angles, beam.axis );
00363                 trap_R_AddRefEntityToScene( &beam );
00364         }
00365 */
00366 }
00367 
00368 
00369 /*
00370 ========================
00371 CG_AddWeaponWithPowerups
00372 ========================
00373 */
00374 static void CG_AddWeaponWithPowerups( refEntity_t *gun, int powerups ) {
00375         // add powerup effects
00376         trap_R_AddRefEntityToScene( gun );
00377 
00378         if (cg.predictedPlayerState.electrifyTime > cg.time)
00379         { //add electrocution shell
00380                 int preShader = gun->customShader;
00381                 if ( rand() & 1 )
00382                 {
00383                         gun->customShader = cgs.media.electricBodyShader;       
00384                 }
00385                 else
00386                 {
00387                         gun->customShader = cgs.media.electricBody2Shader;
00388                 }
00389                 trap_R_AddRefEntityToScene( gun );
00390                 gun->customShader = preShader; //set back just to be safe
00391         }
00392 }
00393 
00394 
00395 /*
00396 =============
00397 CG_AddPlayerWeapon
00398 
00399 Used for both the view weapon (ps is valid) and the world modelother character models (ps is NULL)
00400 The main player will have this called for BOTH cases, so effects like light and
00401 sound should only be done on the world model case.
00402 =============
00403 */
00404 void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team, vec3_t newAngles, qboolean thirdPerson ) {
00405         refEntity_t     gun;
00406         refEntity_t     barrel;
00407         vec3_t          angles;
00408         weapon_t        weaponNum;
00409         weaponInfo_t    *weapon;
00410         centity_t       *nonPredictedCent;
00411         refEntity_t     flash;
00412 
00413         weaponNum = cent->currentState.weapon;
00414 
00415         if (cent->currentState.weapon == WP_EMPLACED_GUN)
00416         {
00417                 return;
00418         }
00419 
00420         if (cg.predictedPlayerState.pm_type == PM_SPECTATOR &&
00421                 cent->currentState.number == cg.predictedPlayerState.clientNum)
00422         { //spectator mode, don't draw it...
00423                 return;
00424         }
00425 
00426         CG_RegisterWeapon( weaponNum );
00427         weapon = &cg_weapons[weaponNum];
00428 /*
00429 Ghoul2 Insert Start
00430 */
00431 
00432         memset( &gun, 0, sizeof( gun ) );
00433 
00434         // only do this if we are in first person, since world weapons are now handled on the server by Ghoul2
00435         if (!thirdPerson)
00436         {
00437 
00438                 // add the weapon
00439                 VectorCopy( parent->lightingOrigin, gun.lightingOrigin );
00440                 gun.shadowPlane = parent->shadowPlane;
00441                 gun.renderfx = parent->renderfx;
00442 
00443                 if (ps)
00444                 {       // this player, in first person view
00445                         gun.hModel = weapon->viewModel;
00446                 }
00447                 else
00448                 {
00449                         gun.hModel = weapon->weaponModel;
00450                 }
00451                 if (!gun.hModel) {
00452                         return;
00453                 }
00454 
00455                 if ( !ps ) {
00456                         // add weapon ready sound
00457                         cent->pe.lightningFiring = qfalse;
00458                         if ( ( cent->currentState.eFlags & EF_FIRING ) && weapon->firingSound ) {
00459                                 // lightning gun and guantlet make a different sound when fire is held down
00460                                 trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->firingSound );
00461                                 cent->pe.lightningFiring = qtrue;
00462                         } else if ( weapon->readySound ) {
00463                                 trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->readySound );
00464                         }
00465                 }
00466         
00467                 CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon");
00468 
00469                 if (!CG_IsMindTricked(cent->currentState.trickedentindex,
00470                         cent->currentState.trickedentindex2,
00471                         cent->currentState.trickedentindex3,
00472                         cent->currentState.trickedentindex4,
00473                         cg.snap->ps.clientNum))
00474                 {
00475                         CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups ); //don't draw the weapon if the player is invisible
00476                         /*
00477                         if ( weaponNum == WP_STUN_BATON )
00478                         {
00479                                 gun.shaderRGBA[0] = gun.shaderRGBA[1] = gun.shaderRGBA[2] = 25;
00480         
00481                                 gun.customShader = trap_R_RegisterShader( "gfx/effects/stunPass" );
00482                                 gun.renderfx = RF_RGB_TINT | RF_FIRST_PERSON | RF_DEPTHHACK;
00483                                 trap_R_AddRefEntityToScene( &gun );
00484                         }
00485                         */
00486                 }
00487 
00488                 if (weaponNum == WP_STUN_BATON)
00489                 {
00490                         int i = 0;
00491 
00492                         while (i < 3)
00493                         {
00494                                 memset( &barrel, 0, sizeof( barrel ) );
00495                                 VectorCopy( parent->lightingOrigin, barrel.lightingOrigin );
00496                                 barrel.shadowPlane = parent->shadowPlane;
00497                                 barrel.renderfx = parent->renderfx;
00498 
00499                                 if (i == 0)
00500                                 {
00501                                         barrel.hModel = trap_R_RegisterModel("models/weapons2/stun_baton/baton_barrel.md3");
00502                                 }
00503                                 else if (i == 1)
00504                                 {
00505                                         barrel.hModel = trap_R_RegisterModel("models/weapons2/stun_baton/baton_barrel2.md3");
00506                                 }
00507                                 else
00508                                 {
00509                                         barrel.hModel = trap_R_RegisterModel("models/weapons2/stun_baton/baton_barrel3.md3");
00510                                 }
00511                                 angles[YAW] = 0;
00512                                 angles[PITCH] = 0;
00513                                 angles[ROLL] = 0;
00514 
00515                                 AnglesToAxis( angles, barrel.axis );
00516 
00517                                 if (i == 0)
00518                                 {
00519                                         CG_PositionRotatedEntityOnTag( &barrel, parent/*&gun*/, /*weapon->weaponModel*/weapon->handsModel, "tag_barrel" );
00520                                 }
00521                                 else if (i == 1)
00522                                 {
00523                                         CG_PositionRotatedEntityOnTag( &barrel, parent/*&gun*/, /*weapon->weaponModel*/weapon->handsModel, "tag_barrel2" );
00524                                 }
00525                                 else
00526                                 {
00527                                         CG_PositionRotatedEntityOnTag( &barrel, parent/*&gun*/, /*weapon->weaponModel*/weapon->handsModel, "tag_barrel3" );
00528                                 }
00529                                 CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups );
00530 
00531                                 i++;
00532                         }
00533                 }
00534                 else
00535                 {
00536                         // add the spinning barrel
00537                         if ( weapon->barrelModel ) {
00538                                 memset( &barrel, 0, sizeof( barrel ) );
00539                                 VectorCopy( parent->lightingOrigin, barrel.lightingOrigin );
00540                                 barrel.shadowPlane = parent->shadowPlane;
00541                                 barrel.renderfx = parent->renderfx;
00542 
00543                                 barrel.hModel = weapon->barrelModel;
00544                                 angles[YAW] = 0;
00545                                 angles[PITCH] = 0;
00546                                 angles[ROLL] = 0;
00547 
00548                                 AnglesToAxis( angles, barrel.axis );
00549 
00550                                 CG_PositionRotatedEntityOnTag( &barrel, parent/*&gun*/, /*weapon->weaponModel*/weapon->handsModel, "tag_barrel" );
00551 
00552                                 CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups );
00553                         }
00554                 }
00555         }
00556 /*
00557 Ghoul2 Insert End
00558 */
00559 
00560         memset (&flash, 0, sizeof(flash));
00561         CG_PositionEntityOnTag( &flash, &gun, gun.hModel, "tag_flash");
00562 
00563         VectorCopy(flash.origin, cg.lastFPFlashPoint);
00564 
00565         // Do special charge bits
00566         //-----------------------
00567         if ( (ps || cg.renderingThirdPerson || cg.predictedPlayerState.clientNum != cent->currentState.number) &&
00568                 ( ( cent->currentState.modelindex2 == WEAPON_CHARGING_ALT && cent->currentState.weapon == WP_BRYAR_PISTOL ) ||
00569                   ( cent->currentState.modelindex2 == WEAPON_CHARGING_ALT && cent->currentState.weapon == WP_BRYAR_OLD ) ||
00570                   ( cent->currentState.weapon == WP_BOWCASTER && cent->currentState.modelindex2 == WEAPON_CHARGING ) ||
00571                   ( cent->currentState.weapon == WP_DEMP2 && cent->currentState.modelindex2 == WEAPON_CHARGING_ALT) ) )
00572         {
00573                 int             shader = 0;
00574                 float   val = 0.0f;
00575                 float   scale = 1.0f;
00576                 addspriteArgStruct_t fxSArgs;
00577                 vec3_t flashorigin, flashdir;
00578 
00579                 if (!thirdPerson)
00580                 {
00581                         VectorCopy(flash.origin, flashorigin);
00582                         VectorCopy(flash.axis[0], flashdir);
00583                 }
00584                 else
00585                 {
00586                         mdxaBone_t              boltMatrix;
00587 
00588                         if (!trap_G2API_HasGhoul2ModelOnIndex(&(cent->ghoul2), 1))
00589                         { //it's quite possible that we may have have no weapon model and be in a valid state, so return here if this is the case
00590                                 return;
00591                         }
00592 
00593                         // go away and get me the bolt position for this frame please
00594                         if (!(trap_G2API_GetBoltMatrix(cent->ghoul2, 1, 0, &boltMatrix, newAngles, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale)))
00595                         {       // Couldn't find bolt point.
00596                                 return;
00597                         }
00598                         
00599                         BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, flashorigin);
00600                         BG_GiveMeVectorFromMatrix(&boltMatrix, POSITIVE_X, flashdir);
00601                 }
00602 
00603                 if ( cent->currentState.weapon == WP_BRYAR_PISTOL ||
00604                         cent->currentState.weapon == WP_BRYAR_OLD)
00605                 {
00606                         // Hardcoded max charge time of 1 second
00607                         val = ( cg.time - cent->currentState.constantLight ) * 0.001f;
00608                         shader = cgs.media.bryarFrontFlash;
00609                 }
00610                 else if ( cent->currentState.weapon == WP_BOWCASTER )
00611                 {
00612                         // Hardcoded max charge time of 1 second
00613                         val = ( cg.time - cent->currentState.constantLight ) * 0.001f;
00614                         shader = cgs.media.greenFrontFlash;
00615                 }
00616                 else if ( cent->currentState.weapon == WP_DEMP2 )
00617                 {
00618                         val = ( cg.time - cent->currentState.constantLight ) * 0.001f;
00619                         shader = cgs.media.lightningFlash;
00620                         scale = 1.75f;
00621                 }
00622 
00623                 if ( val < 0.0f )
00624                 {
00625                         val = 0.0f;
00626                 }
00627                 else if ( val > 1.0f )
00628                 {
00629                         val = 1.0f;
00630                         if (ps && cent->currentState.number == ps->clientNum)
00631                         {
00632                                 CGCam_Shake( /*0.1f*/0.2f, 100 );
00633                         }
00634                 }
00635                 else
00636                 {
00637                         if (ps && cent->currentState.number == ps->clientNum)
00638                         {
00639                                 CGCam_Shake( val * val * /*0.3f*/0.6f, 100 );
00640                         }
00641                 }
00642 
00643                 val += random() * 0.5f;
00644 
00645                 VectorCopy(flashorigin, fxSArgs.origin);
00646                 VectorClear(fxSArgs.vel);
00647                 VectorClear(fxSArgs.accel);
00648                 fxSArgs.scale = 3.0f*val*scale;
00649                 fxSArgs.dscale = 0.0f;
00650                 fxSArgs.sAlpha = 0.7f;
00651                 fxSArgs.eAlpha = 0.7f;
00652                 fxSArgs.rotation = random()*360;
00653                 fxSArgs.bounce = 0.0f;
00654                 fxSArgs.life = 1.0f;
00655                 fxSArgs.shader = shader;
00656                 fxSArgs.flags = 0x08000000;
00657 
00658                 //FX_AddSprite( flash.origin, NULL, NULL, 3.0f * val, 0.0f, 0.7f, 0.7f, WHITE, WHITE, random() * 360, 0.0f, 1.0f, shader, FX_USE_ALPHA );
00659                 trap_FX_AddSprite(&fxSArgs);
00660         }
00661 
00662         // make sure we aren't looking at cg.predictedPlayerEntity for LG
00663         nonPredictedCent = &cg_entities[cent->currentState.clientNum];
00664 
00665         // if the index of the nonPredictedCent is not the same as the clientNum
00666         // then this is a fake player (like on teh single player podiums), so
00667         // go ahead and use the cent
00668         if( ( nonPredictedCent - cg_entities ) != cent->currentState.clientNum ) {
00669                 nonPredictedCent = cent;
00670         }
00671 
00672         // add the flash
00673         if ( ( weaponNum == WP_DEMP2)
00674                 && ( nonPredictedCent->currentState.eFlags & EF_FIRING ) ) 
00675         {
00676                 // continuous flash
00677         } else {
00678                 // impulse flash
00679                 if ( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME) {
00680                         return;
00681                 }
00682         }
00683 
00684         if ( ps || cg.renderingThirdPerson ||
00685                         cent->currentState.number != cg.predictedPlayerState.clientNum ) 
00686         {       // Make sure we don't do the thirdperson model effects for the local player if we're in first person
00687                 vec3_t flashorigin, flashdir;
00688                 refEntity_t     flash;
00689 
00690                 memset (&flash, 0, sizeof(flash));
00691 
00692                 if (!thirdPerson)
00693                 {
00694                         CG_PositionEntityOnTag( &flash, &gun, gun.hModel, "tag_flash");
00695                         VectorCopy(flash.origin, flashorigin);
00696                         VectorCopy(flash.axis[0], flashdir);
00697                 }
00698                 else
00699                 {
00700                         mdxaBone_t              boltMatrix;
00701 
00702                         if (!trap_G2API_HasGhoul2ModelOnIndex(&(cent->ghoul2), 1))
00703                         { //it's quite possible that we may have have no weapon model and be in a valid state, so return here if this is the case
00704                                 return;
00705                         }
00706 
00707                         // go away and get me the bolt position for this frame please
00708                         if (!(trap_G2API_GetBoltMatrix(cent->ghoul2, 1, 0, &boltMatrix, newAngles, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale)))
00709                         {       // Couldn't find bolt point.
00710                                 return;
00711                         }
00712                         
00713                         BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, flashorigin);
00714                         BG_GiveMeVectorFromMatrix(&boltMatrix, POSITIVE_X, flashdir);
00715                 }
00716 
00717                 if ( cg.time - cent->muzzleFlashTime <= MUZZLE_FLASH_TIME + 10 )
00718                 {       // Handle muzzle flashes
00719                         if ( cent->currentState.eFlags & EF_ALT_FIRING )
00720                         {       // Check the alt firing first.
00721                                 if (weapon->altMuzzleEffect)
00722                                 {
00723                                         if (!thirdPerson)
00724                                         {
00725                                                 trap_FX_PlayEntityEffectID(weapon->altMuzzleEffect, flashorigin, flash.axis, -1, -1, -1, -1  );
00726                                         }
00727                                         else
00728                                         {
00729                                                 trap_FX_PlayEffectID(weapon->altMuzzleEffect, flashorigin, flashdir, -1, -1);
00730                                         }
00731                                 }
00732                         }
00733                         else
00734                         {       // Regular firing
00735                                 if (weapon->muzzleEffect)
00736                                 {
00737                                         if (!thirdPerson)
00738                                         {
00739                                                 trap_FX_PlayEntityEffectID(weapon->muzzleEffect, flashorigin, flash.axis, -1, -1, -1, -1  );
00740                                         }
00741                                         else
00742                                         {
00743                                                 trap_FX_PlayEffectID(weapon->muzzleEffect, flashorigin, flashdir, -1, -1);
00744                                         }
00745                                 }
00746                         }
00747                 }
00748 
00749                 // add lightning bolt
00750                 CG_LightningBolt( nonPredictedCent, flashorigin );
00751 
00752                 if ( weapon->flashDlightColor[0] || weapon->flashDlightColor[1] || weapon->flashDlightColor[2] ) {
00753                         trap_R_AddLightToScene( flashorigin, 300 + (rand()&31), weapon->flashDlightColor[0],
00754                                 weapon->flashDlightColor[1], weapon->flashDlightColor[2] );
00755                 }
00756         }
00757 }
00758 
00759 /*
00760 ==============
00761 CG_AddViewWeapon
00762 
00763 Add the weapon, and flash for the player's view
00764 ==============
00765 */
00766 void CG_AddViewWeapon( playerState_t *ps ) {
00767         refEntity_t     hand;
00768         centity_t       *cent;
00769         clientInfo_t    *ci;
00770         float           fovOffset;
00771         vec3_t          angles;
00772         weaponInfo_t    *weapon;
00773         float   cgFov = cg_fov.value;
00774 
00775         if (cgFov < 1)
00776         {
00777                 cgFov = 1;
00778         }
00779         if (cgFov > 97)
00780         {
00781                 cgFov = 97;
00782         }
00783 
00784         if ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
00785                 return;
00786         }
00787 
00788         if ( ps->pm_type == PM_INTERMISSION ) {
00789                 return;
00790         }
00791 
00792         // no gun if in third person view or a camera is active
00793         //if ( cg.renderingThirdPerson || cg.cameraMode) {
00794         if ( cg.renderingThirdPerson ) {
00795                 return;
00796         }
00797 
00798         // allow the gun to be completely removed
00799         if ( !cg_drawGun.integer || cg.predictedPlayerState.zoomMode) {
00800                 vec3_t          origin;
00801 
00802                 if ( cg.predictedPlayerState.eFlags & EF_FIRING ) {
00803                         // special hack for lightning gun...
00804                         VectorCopy( cg.refdef.vieworg, origin );
00805                         VectorMA( origin, -8, cg.refdef.viewaxis[2], origin );
00806                         CG_LightningBolt( &cg_entities[ps->clientNum], origin );
00807                 }
00808                 return;
00809         }
00810 
00811         // don't draw if testing a gun model
00812         if ( cg.testGun ) {
00813                 return;
00814         }
00815 
00816         // drop gun lower at higher fov
00817         if ( cgFov > 90 ) {
00818                 fovOffset = -0.2 * ( cgFov - 90 );
00819         } else {
00820                 fovOffset = 0;
00821         }
00822 
00823         cent = &cg_entities[cg.predictedPlayerState.clientNum];
00824         CG_RegisterWeapon( ps->weapon );
00825         weapon = &cg_weapons[ ps->weapon ];
00826 
00827         memset (&hand, 0, sizeof(hand));
00828 
00829         // set up gun position
00830         CG_CalculateWeaponPosition( hand.origin, angles );
00831 
00832         VectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[0], hand.origin );
00833         VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[1], hand.origin );
00834         VectorMA( hand.origin, (cg_gun_z.value+fovOffset), cg.refdef.viewaxis[2], hand.origin );
00835 
00836         AnglesToAxis( angles, hand.axis );
00837 
00838         // map torso animations to weapon animations
00839         if ( cg_gun_frame.integer ) {
00840                 // development tool
00841                 hand.frame = hand.oldframe = cg_gun_frame.integer;
00842                 hand.backlerp = 0;
00843         } else {
00844                 // get clientinfo for animation map
00845                 if (cent->currentState.eType == ET_NPC)
00846                 {
00847                         if (!cent->npcClient)
00848                         {
00849                                 return;
00850                         }
00851 
00852                         ci = cent->npcClient;
00853                 }
00854                 else
00855                 {
00856                         ci = &cgs.clientinfo[ cent->currentState.clientNum ];
00857                 }
00858                 hand.frame = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.frame, cent->currentState.torsoAnim );
00859                 hand.oldframe = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.oldFrame, cent->currentState.torsoAnim );
00860                 hand.backlerp = cent->pe.torso.backlerp;
00861 
00862                 // Handle the fringe situation where oldframe is invalid
00863                 if ( hand.frame == -1 )
00864                 {
00865                         hand.frame = 0;
00866                         hand.oldframe = 0;
00867                         hand.backlerp = 0;
00868                 }
00869                 else if ( hand.oldframe == -1 )
00870                 {
00871                         hand.oldframe = hand.frame;
00872                         hand.backlerp = 0;
00873                 }
00874         }
00875 
00876         hand.hModel = weapon->handsModel;
00877         hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON;// | RF_MINLIGHT;
00878 
00879         // add everything onto the hand
00880         CG_AddPlayerWeapon( &hand, ps, &cg_entities[cg.predictedPlayerState.clientNum], ps->persistant[PERS_TEAM], angles, qfalse );
00881 }
00882 
00883 /*
00884 ==============================================================================
00885 
00886 WEAPON SELECTION
00887 
00888 ==============================================================================
00889 */
00890 #define ICON_WEAPONS    0
00891 #define ICON_FORCE              1
00892 #define ICON_INVENTORY  2
00893 
00894 
00895 void CG_DrawIconBackground(void)
00896 {
00897         int                             height,xAdd,x2,y2,t;
00898 //      int                             prongLeftX,prongRightX;
00899         float                   inTime = cg.invenSelectTime+WEAPON_SELECT_TIME;
00900         float                   wpTime = cg.weaponSelectTime+WEAPON_SELECT_TIME;
00901         float                   fpTime = cg.forceSelectTime+WEAPON_SELECT_TIME;
00902 //      int                             drawType = cgs.media.weaponIconBackground;
00903 //      int                             yOffset = 0;
00904 
00905 #ifdef _XBOX
00906         //yOffset = -50;
00907 #endif
00908 
00909         // don't display if dead
00910         if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) 
00911         {
00912                 return;
00913         }
00914 
00915         if (cg_hudFiles.integer)
00916         { //simple hud
00917                 return;
00918         }
00919 
00920         x2 = 30;
00921         y2 = SCREEN_HEIGHT-70;
00922 
00923         //prongLeftX =x2+37; 
00924         //prongRightX =x2+544; 
00925 
00926         if (inTime > wpTime)
00927         {
00928 //              drawType = cgs.media.inventoryIconBackground;
00929                 cg.iconSelectTime = cg.invenSelectTime;
00930         }
00931         else
00932         {
00933 //              drawType = cgs.media.weaponIconBackground;
00934                 cg.iconSelectTime = cg.weaponSelectTime;
00935         }
00936 
00937         if (fpTime > inTime && fpTime > wpTime)
00938         {
00939 //              drawType = cgs.media.forceIconBackground;
00940                 cg.iconSelectTime = cg.forceSelectTime;
00941         }
00942 
00943         if ((cg.iconSelectTime+WEAPON_SELECT_TIME)<cg.time)     // Time is up for the HUD to display
00944         {
00945                 if (cg.iconHUDActive)           // The time is up, but we still need to move the prongs back to their original position
00946                 {
00947                         t =  cg.time - (cg.iconSelectTime+WEAPON_SELECT_TIME);
00948                         cg.iconHUDPercent = t/ 130.0f;
00949                         cg.iconHUDPercent = 1 - cg.iconHUDPercent;
00950 
00951                         if (cg.iconHUDPercent<0)
00952                         {
00953                                 cg.iconHUDActive = qfalse;
00954                                 cg.iconHUDPercent=0;
00955                         }
00956 
00957                         xAdd = (int) 8*cg.iconHUDPercent;
00958 
00959                         height = (int) (60.0f*cg.iconHUDPercent);
00960                         //CG_DrawPic( x2+60, y2+30+yOffset, 460, -height, drawType);    // Top half
00961                         //CG_DrawPic( x2+60, y2+30-2+yOffset, 460, height, drawType);   // Bottom half
00962 
00963                 }
00964                 else
00965                 {
00966                         xAdd = 0;
00967                 }
00968 
00969                 return;
00970         }
00971         //prongLeftX =x2+37; 
00972         //prongRightX =x2+544; 
00973 
00974         if (!cg.iconHUDActive)
00975         {
00976                 t = cg.time - cg.iconSelectTime;
00977                 cg.iconHUDPercent = t/ 130.0f;
00978 
00979                 // Calc how far into opening sequence we are
00980                 if (cg.iconHUDPercent>1)
00981                 {
00982                         cg.iconHUDActive = qtrue;
00983                         cg.iconHUDPercent=1;
00984                 }
00985                 else if (cg.iconHUDPercent<0)
00986                 {
00987                         cg.iconHUDPercent=0;
00988                 }
00989         }
00990         else
00991         {
00992                 cg.iconHUDPercent=1;
00993         }
00994 
00995         //trap_R_SetColor( colorTable[CT_WHITE] );                                      
00996         //height = (int) (60.0f*cg.iconHUDPercent);
00997         //CG_DrawPic( x2+60, y2+30+yOffset, 460, -height, drawType);    // Top half
00998         //CG_DrawPic( x2+60, y2+30-2+yOffset, 460, height, drawType);   // Bottom half
00999 
01000         // And now for the prongs
01001 /*      if ((cg.inventorySelectTime+WEAPON_SELECT_TIME)>cg.time)        
01002         {
01003                 cgs.media.currentBackground = ICON_INVENTORY;
01004                 background = &cgs.media.inventoryProngsOn;
01005         }
01006         else if ((cg.weaponSelectTime+WEAPON_SELECT_TIME)>cg.time)      
01007         {
01008                 cgs.media.currentBackground = ICON_WEAPONS;
01009         }
01010         else 
01011         {
01012                 cgs.media.currentBackground = ICON_FORCE;
01013                 background = &cgs.media.forceProngsOn;
01014         }
01015 */
01016         // Side Prongs
01017 //      trap_R_SetColor( colorTable[CT_WHITE]);                                 
01018 //      xAdd = (int) 8*cg.iconHUDPercent;
01019 //      CG_DrawPic( prongLeftX+xAdd, y2-10, 40, 80, background);
01020 //      CG_DrawPic( prongRightX-xAdd, y2-10, -40, 80, background);
01021 
01022 }
01023 
01024 qboolean CG_WeaponCheck(int weap)
01025 {
01026         if (cg.snap->ps.ammo[weaponData[weap].ammoIndex] < weaponData[weap].energyPerShot &&
01027                 cg.snap->ps.ammo[weaponData[weap].ammoIndex] < weaponData[weap].altEnergyPerShot)
01028         {
01029                 return qfalse;
01030         }
01031 
01032         return qtrue;
01033 }
01034 
01035 /*
01036 ===============
01037 CG_WeaponSelectable
01038 ===============
01039 */
01040 static qboolean CG_WeaponSelectable( int i ) {
01041         /*if ( !cg.snap->ps.ammo[weaponData[i].ammoIndex] ) {
01042                 return qfalse;
01043         }*/
01044         if (!i)
01045         {
01046                 return qfalse;
01047         }
01048 
01049         if (cg.predictedPlayerState.ammo[weaponData[i].ammoIndex] < weaponData[i].energyPerShot &&
01050                 cg.predictedPlayerState.ammo[weaponData[i].ammoIndex] < weaponData[i].altEnergyPerShot)
01051         {
01052                 return qfalse;
01053         }
01054 
01055         if (i == WP_DET_PACK && cg.predictedPlayerState.ammo[weaponData[i].ammoIndex] < 1 &&
01056                 !cg.predictedPlayerState.hasDetPackPlanted)
01057         {
01058                 return qfalse;
01059         }
01060 
01061         if ( ! (cg.predictedPlayerState.stats[ STAT_WEAPONS ] & ( 1 << i ) ) ) {
01062                 return qfalse;
01063         }
01064 
01065         return qtrue;
01066 }
01067 
01068 /*
01069 ===================
01070 CG_DrawWeaponSelect
01071 ===================
01072 */
01073 #ifdef _XBOX
01074 extern bool CL_ExtendSelectTime(void);
01075 #endif
01076 void CG_DrawWeaponSelect( void ) {
01077         int                             i;
01078         int                             bits;
01079         int                             count;
01080         int                             smallIconSize,bigIconSize;
01081         int                             holdX,x,y,pad;
01082         int                             sideLeftIconCnt,sideRightIconCnt;
01083         int                             sideMax,holdCount,iconCnt;
01084         int                             height;
01085         int             yOffset = 0;
01086         qboolean drewConc = qfalse;
01087 
01088         if (cg.predictedPlayerState.emplacedIndex)
01089         { //can't cycle when on a weapon
01090                 cg.weaponSelectTime = 0;
01091         }
01092 
01093         if ((cg.weaponSelectTime+WEAPON_SELECT_TIME)<cg.time)   // Time is up for the HUD to display
01094         {
01095                 return;
01096         }
01097 
01098         // don't display if dead
01099         if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) 
01100         {
01101                 return;
01102         }
01103 
01104 #ifdef _XBOX
01105         if(CL_ExtendSelectTime()) {
01106                 cg.weaponSelectTime = cg.time;
01107         }
01108 
01109         yOffset = -50;
01110 #endif
01111 
01112         // showing weapon select clears pickup item display, but not the blend blob
01113         cg.itemPickupTime = 0;
01114 
01115         bits = cg.predictedPlayerState.stats[ STAT_WEAPONS ];
01116 
01117         // count the number of weapons owned
01118         count = 0;
01119 
01120         if ( !CG_WeaponSelectable(cg.weaponSelect) &&
01121                 (cg.weaponSelect == WP_THERMAL || cg.weaponSelect == WP_TRIP_MINE) )
01122         { //display this weapon that we don't actually "have" as unhighlighted until it's deselected
01123           //since it's selected we must increase the count to display the proper number of valid selectable weapons
01124                 count++;
01125         }
01126 
01127         for ( i = 1 ; i < WP_NUM_WEAPONS ; i++ ) 
01128         {
01129                 if ( bits & ( 1 << i ) ) 
01130                 {
01131                         if ( CG_WeaponSelectable(i) ||
01132                                 (i != WP_THERMAL && i != WP_TRIP_MINE) )
01133                         {
01134                                 count++;
01135                         }
01136                 }
01137         }
01138 
01139         if (count == 0) // If no weapons, don't display
01140         {
01141                 return;
01142         }
01143 
01144         sideMax = 3;    // Max number of icons on the side
01145 
01146         // Calculate how many icons will appear to either side of the center one
01147         holdCount = count - 1;  // -1 for the center icon
01148         if (holdCount == 0)                     // No icons to either side
01149         {
01150                 sideLeftIconCnt = 0;
01151                 sideRightIconCnt = 0;
01152         }
01153         else if (count > (2*sideMax))   // Go to the max on each side
01154         {
01155                 sideLeftIconCnt = sideMax;
01156                 sideRightIconCnt = sideMax;
01157         }
01158         else                                                    // Less than max, so do the calc
01159         {
01160                 sideLeftIconCnt = holdCount/2;
01161                 sideRightIconCnt = holdCount - sideLeftIconCnt;
01162         }
01163 
01164         if ( cg.weaponSelect == WP_CONCUSSION )
01165         {
01166                 i = WP_FLECHETTE;
01167         }
01168         else
01169         {
01170                 i = cg.weaponSelect - 1;
01171         }
01172         if (i<1)
01173         {
01174                 i = LAST_USEABLE_WEAPON;
01175         }
01176 
01177         smallIconSize = 40;
01178         bigIconSize = 80;
01179         pad = 12;
01180 
01181         x = 320;
01182         y = 410;
01183 
01184         // Background
01185 //      memcpy(calcColor, colorTable[CT_WHITE], sizeof(vec4_t));
01186 //      calcColor[3] = .35f;
01187 //      trap_R_SetColor( calcColor);                                    
01188 
01189         // Left side ICONS
01190         trap_R_SetColor(colorTable[CT_WHITE]);
01191         // Work backwards from current icon
01192         holdX = x - ((bigIconSize/2) + pad + smallIconSize);
01193         height = smallIconSize * 1;//cg.iconHUDPercent;
01194         drewConc = qfalse;
01195 
01196         for (iconCnt=1;iconCnt<(sideLeftIconCnt+1);i--)
01197         {
01198                 if ( i == WP_CONCUSSION )
01199                 {
01200                         i--;
01201                 }
01202                 else if ( i == WP_FLECHETTE && !drewConc && cg.weaponSelect != WP_CONCUSSION )
01203                 {
01204                         i = WP_CONCUSSION;
01205                 }
01206                 if (i<1)
01207                 {
01208                         //i = 13;
01209                         //...don't ever do this.
01210                         i = LAST_USEABLE_WEAPON;
01211                 }
01212 
01213                 if ( !(bits & ( 1 << i )))      // Does he have this weapon?
01214                 {
01215                         if ( i == WP_CONCUSSION )
01216                         {
01217                                 drewConc = qtrue;
01218                                 i = WP_ROCKET_LAUNCHER;
01219                         }
01220                         continue;
01221                 }
01222 
01223                 if ( !CG_WeaponSelectable(i) &&
01224                         (i == WP_THERMAL || i == WP_TRIP_MINE) )
01225                 { //Don't show thermal and tripmine when out of them
01226                         continue;
01227                 }
01228 
01229                 ++iconCnt;                                      // Good icon
01230 
01231                 if (cgs.media.weaponIcons[i])
01232                 {
01233                         weaponInfo_t    *weaponInfo;
01234                         CG_RegisterWeapon( i ); 
01235                         weaponInfo = &cg_weapons[i];
01236 
01237                         trap_R_SetColor(colorTable[CT_WHITE]);
01238                         if (!CG_WeaponCheck(i))
01239                         {
01240                                 CG_DrawPic( holdX, y+10+yOffset, smallIconSize, smallIconSize, /*weaponInfo->weaponIconNoAmmo*/cgs.media.weaponIcons_NA[i] );
01241                         }
01242                         else
01243                         {
01244                                 CG_DrawPic( holdX, y+10+yOffset, smallIconSize, smallIconSize, /*weaponInfo->weaponIcon*/cgs.media.weaponIcons[i] );
01245                         }
01246 
01247                         holdX -= (smallIconSize+pad);
01248                 }
01249                 if ( i == WP_CONCUSSION )
01250                 {
01251                         drewConc = qtrue;
01252                         i = WP_ROCKET_LAUNCHER;
01253                 }
01254         }
01255 
01256         // Current Center Icon
01257         height = bigIconSize * cg.iconHUDPercent;
01258         if (cgs.media.weaponIcons[cg.weaponSelect])
01259         {
01260                 weaponInfo_t    *weaponInfo;
01261                 CG_RegisterWeapon( cg.weaponSelect );   
01262                 weaponInfo = &cg_weapons[cg.weaponSelect];
01263 
01264                 trap_R_SetColor( colorTable[CT_WHITE]);
01265                 if (!CG_WeaponCheck(cg.weaponSelect))
01266                 {
01267                         CG_DrawPic( x-(bigIconSize/2), (y-((bigIconSize-smallIconSize)/2))+10+yOffset, bigIconSize, bigIconSize, cgs.media.weaponIcons_NA[cg.weaponSelect] );
01268                 }
01269                 else
01270                 {
01271                         CG_DrawPic( x-(bigIconSize/2), (y-((bigIconSize-smallIconSize)/2))+10+yOffset, bigIconSize, bigIconSize, cgs.media.weaponIcons[cg.weaponSelect] );
01272                 }
01273         }
01274 
01275         if ( cg.weaponSelect == WP_CONCUSSION )
01276         {
01277                 i = WP_ROCKET_LAUNCHER;
01278         }
01279         else
01280         {
01281                 i = cg.weaponSelect + 1;
01282         }
01283         if (i> LAST_USEABLE_WEAPON)
01284         {
01285                 i = 1;
01286         }
01287 
01288         // Right side ICONS
01289         // Work forwards from current icon
01290         holdX = x + (bigIconSize/2) + pad;
01291         height = smallIconSize * cg.iconHUDPercent;
01292         for (iconCnt=1;iconCnt<(sideRightIconCnt+1);i++)
01293         {
01294                 if ( i == WP_CONCUSSION )
01295                 {
01296                         i++;
01297                 }
01298                 else if ( i == WP_ROCKET_LAUNCHER && !drewConc && cg.weaponSelect != WP_CONCUSSION )
01299                 {
01300                         i = WP_CONCUSSION;
01301                 }
01302                 if (i>LAST_USEABLE_WEAPON)
01303                 {
01304                         i = 1;
01305                 }
01306 
01307                 if ( !(bits & ( 1 << i )))      // Does he have this weapon?
01308                 {
01309                         if ( i == WP_CONCUSSION )
01310                         {
01311                                 drewConc = qtrue;
01312                                 i = WP_FLECHETTE;
01313                         }
01314                         continue;
01315                 }
01316 
01317                 if ( !CG_WeaponSelectable(i) &&
01318                         (i == WP_THERMAL || i == WP_TRIP_MINE) )
01319                 { //Don't show thermal and tripmine when out of them
01320                         continue;
01321                 }
01322 
01323                 ++iconCnt;                                      // Good icon
01324 
01325                 if (/*weaponData[i].weaponIcon[0]*/cgs.media.weaponIcons[i])
01326                 {
01327                         weaponInfo_t    *weaponInfo;
01328                         CG_RegisterWeapon( i ); 
01329                         weaponInfo = &cg_weapons[i];
01330                         // No ammo for this weapon?
01331                         trap_R_SetColor( colorTable[CT_WHITE]);
01332                         if (!CG_WeaponCheck(i))
01333                         {
01334                                 CG_DrawPic( holdX, y+10+yOffset, smallIconSize, smallIconSize, cgs.media.weaponIcons_NA[i] );
01335                         }
01336                         else
01337                         {
01338                                 CG_DrawPic( holdX, y+10+yOffset, smallIconSize, smallIconSize, cgs.media.weaponIcons[i] );
01339                         }
01340 
01341 
01342                         holdX += (smallIconSize+pad);
01343                 }
01344                 if ( i == WP_CONCUSSION )
01345                 {
01346                         drewConc = qtrue;
01347                         i = WP_FLECHETTE;
01348                 }
01349         }
01350 
01351         // draw the selected name
01352         if ( cg_weapons[ cg.weaponSelect ].item ) 
01353         {
01354                 vec4_t                  textColor = { .875f, .718f, .121f, 1.0f };
01355                 char    text[1024];
01356                 char    upperKey[1024];
01357 
01358                 strcpy(upperKey, cg_weapons[ cg.weaponSelect ].item->classname);
01359 
01360                 if ( trap_SP_GetStringTextString( va("SP_INGAME_%s",Q_strupr(upperKey)), text, sizeof( text )))
01361                 {
01362                         UI_DrawProportionalString(320, y+45+yOffset, text, UI_CENTER|UI_SMALLFONT, textColor);
01363                 }
01364                 else
01365                 {
01366                         UI_DrawProportionalString(320, y+45+yOffset, cg_weapons[ cg.weaponSelect ].item->classname, UI_CENTER|UI_SMALLFONT, textColor);
01367                 }
01368         }
01369 
01370         trap_R_SetColor( NULL );
01371 }
01372 
01373 
01374 /*
01375 ===============
01376 CG_NextWeapon_f
01377 ===============
01378 */
01379 void CG_NextWeapon_f( void ) {
01380         int             i;
01381         int             original;
01382 
01383         if ( !cg.snap ) {
01384                 return;
01385         }
01386         if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
01387                 return;
01388         }
01389 
01390         if (cg.predictedPlayerState.pm_type == PM_SPECTATOR)
01391         {
01392                 return;
01393         }
01394 
01395         if (cg.snap->ps.emplacedIndex)
01396         {
01397                 return;
01398         }
01399 
01400         cg.weaponSelectTime = cg.time;
01401         original = cg.weaponSelect;
01402 
01403         for ( i = 0 ; i < WP_NUM_WEAPONS ; i++ ) {
01404                 //*SIGH*... Hack to put concussion rifle before rocketlauncher
01405                 if ( cg.weaponSelect == WP_FLECHETTE )
01406                 {
01407                         cg.weaponSelect = WP_CONCUSSION;
01408                 }
01409                 else if ( cg.weaponSelect == WP_CONCUSSION )
01410                 {
01411                         cg.weaponSelect = WP_ROCKET_LAUNCHER;
01412                 }
01413                 else if ( cg.weaponSelect == WP_DET_PACK )
01414                 {
01415                         cg.weaponSelect = WP_BRYAR_OLD;
01416                 }
01417                 else
01418                 {
01419                         cg.weaponSelect++;
01420                 }
01421                 if ( cg.weaponSelect == WP_NUM_WEAPONS ) {
01422                         cg.weaponSelect = 0;
01423                 }
01424         //      if ( cg.weaponSelect == WP_STUN_BATON ) {
01425         //              continue;               // never cycle to gauntlet
01426         //      }
01427                 if ( CG_WeaponSelectable( cg.weaponSelect ) ) {
01428                         break;
01429                 }
01430         }
01431         if ( i == WP_NUM_WEAPONS ) {
01432                 cg.weaponSelect = original;
01433         }
01434         else
01435         {
01436                 trap_S_MuteSound(cg.snap->ps.clientNum, CHAN_WEAPON);
01437         }
01438 }
01439 
01440 /*
01441 ===============
01442 CG_PrevWeapon_f
01443 ===============
01444 */
01445 void CG_PrevWeapon_f( void ) {
01446         int             i;
01447         int             original;
01448 
01449         if ( !cg.snap ) {
01450                 return;
01451         }
01452         if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
01453                 return;
01454         }
01455 
01456         if (cg.predictedPlayerState.pm_type == PM_SPECTATOR)
01457         {
01458                 return;
01459         }
01460 
01461         if (cg.snap->ps.emplacedIndex)
01462         {
01463                 return;
01464         }
01465 
01466         cg.weaponSelectTime = cg.time;
01467         original = cg.weaponSelect;
01468 
01469         for ( i = 0 ; i < WP_NUM_WEAPONS ; i++ ) {
01470                 //*SIGH*... Hack to put concussion rifle before rocketlauncher
01471                 if ( cg.weaponSelect == WP_ROCKET_LAUNCHER )
01472                 {
01473                         cg.weaponSelect = WP_CONCUSSION;
01474                 }
01475                 else if ( cg.weaponSelect == WP_CONCUSSION )
01476                 {
01477                         cg.weaponSelect = WP_FLECHETTE;
01478                 }
01479                 else if ( cg.weaponSelect == WP_BRYAR_OLD )
01480                 {
01481                         cg.weaponSelect = WP_DET_PACK;
01482                 }
01483                 else
01484                 {
01485                         cg.weaponSelect--;
01486                 }
01487                 if ( cg.weaponSelect == -1 ) {
01488                         cg.weaponSelect = WP_NUM_WEAPONS-1;
01489                 }
01490         //      if ( cg.weaponSelect == WP_STUN_BATON ) {
01491         //              continue;               // never cycle to gauntlet
01492         //      }
01493                 if ( CG_WeaponSelectable( cg.weaponSelect ) ) {
01494                         break;
01495                 }
01496         }
01497         if ( i == WP_NUM_WEAPONS ) {
01498                 cg.weaponSelect = original;
01499         }
01500         else
01501         {
01502                 trap_S_MuteSound(cg.snap->ps.clientNum, CHAN_WEAPON);
01503         }
01504 }
01505 
01506 /*
01507 ===============
01508 CG_Weapon_f
01509 ===============
01510 */
01511 void CG_Weapon_f( void ) {
01512         int             num;
01513 
01514         if ( !cg.snap ) {
01515                 return;
01516         }
01517         if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
01518                 return;
01519         }
01520 
01521         if (cg.snap->ps.emplacedIndex)
01522         {
01523                 return;
01524         }
01525 
01526         num = atoi( CG_Argv( 1 ) );
01527 
01528         if ( num < 1 || num > LAST_USEABLE_WEAPON ) {
01529                 return;
01530         }
01531 
01532         if (num == 1 && cg.snap->ps.weapon == WP_SABER)
01533         {
01534                 if (cg.snap->ps.weaponTime < 1)
01535                 {
01536                         trap_SendConsoleCommand("sv_saberswitch\n");
01537                 }
01538                 return;
01539         }
01540 
01541         //rww - hack to make weapon numbers same as single player
01542         if (num > WP_STUN_BATON)
01543         {
01544                 //num++;
01545                 num += 2; //I suppose this is getting kind of crazy, what with the wp_melee in there too now.
01546         }
01547         else
01548         {
01549                 if (cg.snap->ps.stats[STAT_WEAPONS] & (1 << WP_SABER))
01550                 {
01551                         num = WP_SABER;
01552                 }
01553                 else
01554                 {
01555                         num = WP_MELEE;
01556                 }
01557         }
01558 
01559         if (num > LAST_USEABLE_WEAPON+1)
01560         { //other weapons are off limits due to not actually being weapon weapons
01561                 return;
01562         }
01563 
01564         if (num >= WP_THERMAL && num <= WP_DET_PACK)
01565         {
01566                 int weap, i = 0;
01567 
01568                 if (cg.snap->ps.weapon >= WP_THERMAL &&
01569                         cg.snap->ps.weapon <= WP_DET_PACK)
01570                 {
01571                         // already in cycle range so start with next cycle item
01572                         weap = cg.snap->ps.weapon + 1;
01573                 }
01574                 else
01575                 {
01576                         // not in cycle range, so start with thermal detonator
01577                         weap = WP_THERMAL;
01578                 }
01579 
01580                 // prevent an endless loop
01581                 while ( i <= 4 )
01582                 {
01583                         if (weap > WP_DET_PACK)
01584                         {
01585                                 weap = WP_THERMAL;
01586                         }
01587 
01588                         if (CG_WeaponSelectable(weap))
01589                         {
01590                                 num = weap;
01591                                 break;
01592                         }
01593 
01594                         weap++;
01595                         i++;
01596                 }
01597         }
01598 
01599         if (!CG_WeaponSelectable(num))
01600         {
01601                 return;
01602         }
01603 
01604         cg.weaponSelectTime = cg.time;
01605 
01606         if ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) )
01607         {
01608                 if (num == WP_SABER)
01609                 { //don't have saber, try melee on the same slot
01610                         num = WP_MELEE;
01611 
01612                         if ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) )
01613                         {
01614                                 return;
01615                         }
01616                 }
01617                 else
01618                 {
01619                         return;         // don't have the weapon
01620                 }
01621         }
01622 
01623         if (cg.weaponSelect != num)
01624         {
01625                 trap_S_MuteSound(cg.snap->ps.clientNum, CHAN_WEAPON);
01626         }
01627 
01628         cg.weaponSelect = num;
01629 }
01630 
01631 
01632 //Version of the above which doesn't add +2 to a weapon.  The above can't
01633 //triger WP_MELEE or WP_STUN_BATON.  Derogatory comments go here.
01634 void CG_WeaponClean_f( void ) {
01635         int             num;
01636 
01637         if ( !cg.snap ) {
01638                 return;
01639         }
01640         if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
01641                 return;
01642         }
01643 
01644         if (cg.snap->ps.emplacedIndex)
01645         {
01646                 return;
01647         }
01648 
01649         num = atoi( CG_Argv( 1 ) );
01650 
01651         if ( num < 1 || num > LAST_USEABLE_WEAPON ) {
01652                 return;
01653         }
01654 
01655         if (num == 1 && cg.snap->ps.weapon == WP_SABER)
01656         {
01657                 if (cg.snap->ps.weaponTime < 1)
01658                 {
01659                         trap_SendConsoleCommand("sv_saberswitch\n");
01660                 }
01661                 return;
01662         }
01663 
01664         if(num == WP_STUN_BATON) {
01665                 if (cg.snap->ps.stats[STAT_WEAPONS] & (1 << WP_SABER))
01666                 {
01667                         num = WP_SABER;
01668                 }
01669                 else
01670                 {
01671                         num = WP_MELEE;
01672                 }
01673         }
01674 
01675         if (num > LAST_USEABLE_WEAPON+1)
01676         { //other weapons are off limits due to not actually being weapon weapons
01677                 return;
01678         }
01679 
01680         if (num >= WP_THERMAL && num <= WP_DET_PACK)
01681         {
01682                 int weap, i = 0;
01683 
01684                 if (cg.snap->ps.weapon >= WP_THERMAL &&
01685                         cg.snap->ps.weapon <= WP_DET_PACK)
01686                 {
01687                         // already in cycle range so start with next cycle item
01688                         weap = cg.snap->ps.weapon + 1;
01689                 }
01690                 else
01691                 {
01692                         // not in cycle range, so start with thermal detonator
01693                         weap = WP_THERMAL;
01694                 }
01695 
01696                 // prevent an endless loop
01697                 while ( i <= 4 )
01698                 {
01699                         if (weap > WP_DET_PACK)
01700                         {
01701                                 weap = WP_THERMAL;
01702                         }
01703 
01704                         if (CG_WeaponSelectable(weap))
01705                         {
01706                                 num = weap;
01707                                 break;
01708                         }
01709 
01710                         weap++;
01711                         i++;
01712                 }
01713         }
01714 
01715         if (!CG_WeaponSelectable(num))
01716         {
01717                 return;
01718         }
01719 
01720         cg.weaponSelectTime = cg.time;
01721 
01722         if ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) )
01723         {
01724                 if (num == WP_SABER)
01725                 { //don't have saber, try melee on the same slot
01726                         num = WP_MELEE;
01727 
01728                         if ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) )
01729                         {
01730                                 return;
01731                         }
01732                 }
01733                 else
01734                 {
01735                         return;         // don't have the weapon
01736                 }
01737         }
01738 
01739         if (cg.weaponSelect != num)
01740         {
01741                 trap_S_MuteSound(cg.snap->ps.clientNum, CHAN_WEAPON);
01742         }
01743 
01744         cg.weaponSelect = num;
01745 }
01746 
01747 
01748 
01749 /*
01750 ===================
01751 CG_OutOfAmmoChange
01752 
01753 The current weapon has just run out of ammo
01754 ===================
01755 */
01756 void CG_OutOfAmmoChange( int oldWeapon )
01757 {
01758         int             i;
01759 
01760         cg.weaponSelectTime = cg.time;
01761 
01762         for ( i = LAST_USEABLE_WEAPON ; i > 0 ; i-- )   //We don't want the emplaced or turret
01763         {
01764                 if ( CG_WeaponSelectable( i ) )
01765                 {
01766                         /*
01767                         if ( 1 == cg_autoswitch.integer && 
01768                                 ( i == WP_TRIP_MINE || i == WP_DET_PACK || i == WP_THERMAL || i == WP_ROCKET_LAUNCHER) ) // safe weapon switch
01769                         */
01770                         //rww - Don't we want to make sure i != one of these if autoswitch is 1 (safe)?
01771                         if (cg_autoswitch.integer != 1 || (i != WP_TRIP_MINE && i != WP_DET_PACK && i != WP_THERMAL && i != WP_ROCKET_LAUNCHER))
01772                         {
01773                                 if (i != oldWeapon)
01774                                 { //don't even do anything if we're just selecting the weapon we already have/had
01775                                         cg.weaponSelect = i;
01776                                         break;
01777                                 }
01778                         }
01779                 }
01780         }
01781 
01782         trap_S_MuteSound(cg.snap->ps.clientNum, CHAN_WEAPON);
01783 }
01784 
01785 
01786 
01787 /*
01788 ===================================================================================================
01789 
01790 WEAPON EVENTS
01791 
01792 ===================================================================================================
01793 */
01794 
01795 void CG_GetClientWeaponMuzzleBoltPoint(int clIndex, vec3_t to)
01796 {
01797         centity_t *cent;
01798         mdxaBone_t      boltMatrix;
01799 
01800         if (clIndex < 0 || clIndex >= MAX_CLIENTS)
01801         {
01802                 return;
01803         }
01804 
01805         cent = &cg_entities[clIndex];
01806 
01807         if (!cent || !cent->ghoul2 || !trap_G2_HaveWeGhoul2Models(cent->ghoul2) ||
01808                 !trap_G2API_HasGhoul2ModelOnIndex(&(cent->ghoul2), 1))
01809         {
01810                 return;
01811         }
01812 
01813         trap_G2API_GetBoltMatrix(cent->ghoul2, 1, 0, &boltMatrix, cent->turAngles, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale);
01814         BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, to);
01815 }
01816 
01817 /*
01818 ================
01819 CG_FireWeapon
01820 
01821 Caused by an EV_FIRE_WEAPON event
01822 ================
01823 */
01824 void CG_FireWeapon( centity_t *cent, qboolean altFire ) {
01825         entityState_t *ent;
01826         int                             c;
01827         weaponInfo_t    *weap;
01828 
01829         ent = &cent->currentState;
01830         if ( ent->weapon == WP_NONE ) {
01831                 return;
01832         }
01833         if ( ent->weapon >= WP_NUM_WEAPONS ) {
01834                 CG_Error( "CG_FireWeapon: ent->weapon >= WP_NUM_WEAPONS" );
01835                 return;
01836         }
01837         weap = &cg_weapons[ ent->weapon ];
01838 
01839         // mark the entity as muzzle flashing, so when it is added it will
01840         // append the flash to the weapon model
01841         cent->muzzleFlashTime = cg.time;
01842 
01843         if (cg.predictedPlayerState.clientNum == cent->currentState.number)
01844         {
01845                 if ((ent->weapon == WP_BRYAR_PISTOL && altFire) ||
01846                         (ent->weapon == WP_BRYAR_OLD && altFire) ||
01847                         (ent->weapon == WP_BOWCASTER && !altFire) ||
01848                         (ent->weapon == WP_DEMP2 && altFire))
01849                 {
01850                         float val = ( cg.time - cent->currentState.constantLight ) * 0.001f;
01851 
01852                         if (val > 3)
01853                         {
01854                                 val = 3;
01855                         }
01856                         if (val < 0.2)
01857                         {
01858                                 val = 0.2;
01859                         }
01860 
01861                         val *= 2;
01862 
01863                         CGCam_Shake( val, 250 );
01864                 }
01865                 else if (ent->weapon == WP_ROCKET_LAUNCHER ||
01866                         (ent->weapon == WP_REPEATER && altFire) ||
01867                         ent->weapon == WP_FLECHETTE ||
01868                         (ent->weapon == WP_CONCUSSION && !altFire))
01869                 {
01870                         if (ent->weapon == WP_CONCUSSION)
01871                         {
01872                                 if (!cg.renderingThirdPerson )//gives an advantage to being in 3rd person, but would look silly otherwise
01873                                 {//kick the view back
01874                                         cg.kick_angles[PITCH] = flrand( -10, -15 );
01875                                         cg.kick_time = cg.time;
01876                                 }
01877                         }
01878                         else if (ent->weapon == WP_ROCKET_LAUNCHER)
01879                         {
01880                                 CGCam_Shake(flrand(2, 3), 350);
01881                         }
01882                         else if (ent->weapon == WP_REPEATER)
01883                         {
01884                                 CGCam_Shake(flrand(2, 3), 350);
01885                         }
01886                         else if (ent->weapon == WP_FLECHETTE)
01887                         {
01888                                 if (altFire)
01889                                 {
01890                                         CGCam_Shake(flrand(2, 3), 350);
01891                                 }
01892                                 else
01893                                 {
01894                                         CGCam_Shake(1.5, 250);
01895                                 }
01896                         }
01897                 }
01898         }
01899         // lightning gun only does this this on initial press
01900         if ( ent->weapon == WP_DEMP2 ) {
01901                 if ( cent->pe.lightningFiring ) {
01902                         return;
01903                 }
01904         }
01905 
01906         // play quad sound if needed
01907         if ( cent->currentState.powerups & ( 1 << PW_QUAD ) ) {
01908                 //trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.media.quadSound );
01909         }
01910 
01911 
01912         // play a sound
01913         if (altFire)
01914         {
01915                 // play a sound
01916                 for ( c = 0 ; c < 4 ; c++ ) {
01917                         if ( !weap->altFlashSound[c] ) {
01918                                 break;
01919                         }
01920                 }
01921                 if ( c > 0 ) {
01922                         c = rand() % c;
01923                         if ( weap->altFlashSound[c] )
01924                         {
01925                                 trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->altFlashSound[c] );
01926                         }
01927                 }
01928 //              if ( weap->altFlashSnd )
01929 //              {
01930 //                      trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->altFlashSnd );
01931 //              }
01932         }
01933         else
01934         {
01935                 // play a sound
01936                 for ( c = 0 ; c < 4 ; c++ ) {
01937                         if ( !weap->flashSound[c] ) {
01938                                 break;
01939                         }
01940                 }
01941                 if ( c > 0 ) {
01942                         c = rand() % c;
01943                         if ( weap->flashSound[c] )
01944                         {
01945                                 trap_S_StartSound( NULL, ent->number, CHAN_WEAPON, weap->flashSound[c] );
01946                         }
01947                 }
01948         }
01949 }
01950 
01951 qboolean CG_VehicleWeaponImpact( centity_t *cent )
01952 {//see if this is a missile entity that's owned by a vehicle and should do a special, overridden impact effect
01953         if ((cent->currentState.eFlags&EF_JETPACK_ACTIVE)//hack so we know we're a vehicle Weapon shot
01954                 && cent->currentState.otherEntityNum2
01955                 && g_vehWeaponInfo[cent->currentState.otherEntityNum2].iImpactFX)
01956         {//missile is from a special vehWeapon
01957                 vec3_t normal;
01958                 ByteToDir( cent->currentState.eventParm, normal );
01959 
01960                 trap_FX_PlayEffectID( g_vehWeaponInfo[cent->currentState.otherEntityNum2].iImpactFX, cent->lerpOrigin, normal, -1, -1 );
01961                 return qtrue;
01962         }
01963         return qfalse;
01964 }
01965 
01966 /*
01967 =================
01968 CG_MissileHitWall
01969 
01970 Caused by an EV_MISSILE_MISS event, or directly by local bullet tracing
01971 =================
01972 */
01973 void CG_MissileHitWall(int weapon, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType, qboolean altFire, int charge) 
01974 {
01975         int parm;
01976         vec3_t up={0,0,1};
01977 
01978         switch( weapon )
01979         {
01980         case WP_BRYAR_PISTOL:
01981                 if ( altFire )
01982                 {
01983                         parm = charge;
01984                         FX_BryarAltHitWall( origin, dir, parm );
01985                 }
01986                 else
01987                 {
01988                         FX_BryarHitWall( origin, dir );
01989                 }
01990                 break;
01991 
01992         case WP_CONCUSSION:
01993                 FX_ConcussionHitWall( origin, dir );
01994                 break;
01995 
01996         case WP_BRYAR_OLD:
01997                 if ( altFire )
01998                 {
01999                         parm = charge;
02000                         FX_BryarAltHitWall( origin, dir, parm );
02001                 }
02002                 else
02003                 {
02004                         FX_BryarHitWall( origin, dir );
02005                 }
02006                 break;
02007 
02008         case WP_TURRET:
02009                 FX_TurretHitWall( origin, dir );
02010                 break;
02011 
02012         case WP_BLASTER:
02013                 FX_BlasterWeaponHitWall( origin, dir );
02014                 break;
02015 
02016         case WP_DISRUPTOR:
02017                 FX_DisruptorAltMiss( origin, dir );
02018                 break;
02019 
02020         case WP_BOWCASTER:
02021                 FX_BowcasterHitWall( origin, dir );
02022                 break;
02023 
02024         case WP_REPEATER:
02025                 if ( altFire )
02026                 {
02027                         FX_RepeaterAltHitWall( origin, dir );
02028                 }
02029                 else
02030                 {
02031                         FX_RepeaterHitWall( origin, dir );
02032                 }
02033                 break;
02034 
02035         case WP_DEMP2:
02036                 if (altFire)
02037                 {
02038                         trap_FX_PlayEffectID(cgs.effects.mAltDetonate, origin, dir, -1, -1);
02039                 }
02040                 else
02041                 {
02042                         FX_DEMP2_HitWall( origin, dir );
02043                 }
02044                 break;
02045 
02046         case WP_FLECHETTE:
02047                 /*if (altFire)
02048                 {
02049                         CG_SurfaceExplosion(origin, dir, 20.0f, 12.0f, qtrue);
02050                 }
02051                 else
02052                 */
02053                 if (!altFire)
02054                 {
02055                         FX_FlechetteWeaponHitWall( origin, dir );
02056                 }
02057                 break;
02058 
02059         case WP_ROCKET_LAUNCHER:
02060                 FX_RocketHitWall( origin, dir );
02061                 break;
02062 
02063         case WP_THERMAL:
02064                 trap_FX_PlayEffectID( cgs.effects.thermalExplosionEffect, origin, dir, -1, -1 );
02065                 trap_FX_PlayEffectID( cgs.effects.thermalShockwaveEffect, origin, up, -1, -1 );
02066                 break;
02067 
02068         case WP_EMPLACED_GUN:
02069                 FX_BlasterWeaponHitWall( origin, dir );
02070                 //FIXME: Give it its own hit wall effect
02071                 break;
02072         }
02073 }
02074 
02075 
02076 /*
02077 =================
02078 CG_MissileHitPlayer
02079 =================
02080 */
02081 void CG_MissileHitPlayer(int weapon, vec3_t origin, vec3_t dir, int entityNum, qboolean altFire) 
02082 {
02083         qboolean        humanoid = qtrue;
02084         vec3_t up={0,0,1};
02085 
02086         /*
02087         // NOTENOTE Non-portable code from single player
02088         if ( cent->gent )
02089         {
02090                 other = &g_entities[cent->gent->s.otherEntityNum];
02091 
02092                 if ( other->client && other->client->playerTeam == TEAM_BOTS )
02093                 {
02094                         humanoid = qfalse;
02095                 }
02096         }
02097         */      
02098 
02099         // NOTENOTE No bleeding in this game
02100 //      CG_Bleed( origin, entityNum );
02101 
02102         // some weapons will make an explosion with the blood, while
02103         // others will just make the blood
02104         switch ( weapon ) {
02105         case WP_BRYAR_PISTOL:
02106                 if ( altFire )
02107                 {
02108                         FX_BryarAltHitPlayer( origin, dir, humanoid );
02109                 }
02110                 else
02111                 {
02112                         FX_BryarHitPlayer( origin, dir, humanoid );
02113                 }
02114                 break;
02115 
02116         case WP_CONCUSSION:
02117                 FX_ConcussionHitPlayer( origin, dir, humanoid );
02118                 break;
02119 
02120         case WP_BRYAR_OLD:
02121                 if ( altFire )
02122                 {
02123                         FX_BryarAltHitPlayer( origin, dir, humanoid );
02124                 }
02125                 else
02126                 {
02127                         FX_BryarHitPlayer( origin, dir, humanoid );
02128                 }
02129                 break;
02130 
02131         case WP_TURRET:
02132                 FX_TurretHitPlayer( origin, dir, humanoid );
02133                 break;
02134 
02135         case WP_BLASTER:
02136                 FX_BlasterWeaponHitPlayer( origin, dir, humanoid );
02137                 break;
02138 
02139         case WP_DISRUPTOR:
02140                 FX_DisruptorAltHit( origin, dir);
02141                 break;
02142 
02143         case WP_BOWCASTER:
02144                 FX_BowcasterHitPlayer( origin, dir, humanoid );
02145                 break;
02146 
02147         case WP_REPEATER:
02148                 if ( altFire )
02149                 {
02150                         FX_RepeaterAltHitPlayer( origin, dir, humanoid );
02151                 }
02152                 else
02153                 {
02154                         FX_RepeaterHitPlayer( origin, dir, humanoid );
02155                 }
02156                 break;
02157 
02158         case WP_DEMP2:
02159                 // Do a full body effect here for some more feedback
02160                 // NOTENOTE The chaining of the demp2 is not yet implemented.
02161                 /*
02162                 if ( other )
02163                 {
02164                         other->s.powerups |= ( 1 << PW_DISINT_1 );
02165                         other->client->ps.powerups[PW_DISINT_1] = cg.time + 650;
02166                 }
02167                 */
02168                 if (altFire)
02169                 {
02170                         trap_FX_PlayEffectID(cgs.effects.mAltDetonate, origin, dir, -1, -1);
02171                 }
02172                 else
02173                 {
02174                         FX_DEMP2_HitPlayer( origin, dir, humanoid );
02175                 }
02176                 break;
02177 
02178         case WP_FLECHETTE:
02179                 FX_FlechetteWeaponHitPlayer( origin, dir, humanoid );
02180                 break;
02181 
02182         case WP_ROCKET_LAUNCHER:
02183                 FX_RocketHitPlayer( origin, dir, humanoid );
02184                 break;
02185 
02186         case WP_THERMAL:
02187                 trap_FX_PlayEffectID( cgs.effects.thermalExplosionEffect, origin, dir, -1, -1 );
02188                 trap_FX_PlayEffectID( cgs.effects.thermalShockwaveEffect, origin, up, -1, -1 );
02189                 break;
02190         case WP_EMPLACED_GUN:
02191                 //FIXME: Its own effect?
02192                 FX_BlasterWeaponHitPlayer( origin, dir, humanoid );
02193                 break;
02194 
02195         default:
02196                 break;
02197         }
02198 }
02199 
02200 
02201 /*
02202 ============================================================================
02203 
02204 BULLETS
02205 
02206 ============================================================================
02207 */
02208 
02209 
02210 /*
02211 ======================
02212 CG_CalcMuzzlePoint
02213 ======================
02214 */
02215 qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle ) {
02216         vec3_t          forward, right;
02217         vec3_t          gunpoint;
02218         centity_t       *cent;
02219         int                     anim;
02220 
02221         if ( entityNum == cg.snap->ps.clientNum )
02222         { //I'm not exactly sure why we'd be rendering someone else's crosshair, but hey.
02223                 int weapontype = cg.snap->ps.weapon;
02224                 vec3_t weaponMuzzle;
02225                 centity_t *pEnt = &cg_entities[cg.predictedPlayerState.clientNum];
02226 
02227                 VectorCopy(WP_MuzzlePoint[weapontype], weaponMuzzle);
02228 
02229                 if (weapontype == WP_DISRUPTOR || weapontype == WP_STUN_BATON || weapontype == WP_MELEE || weapontype == WP_SABER)
02230                 {
02231                         VectorClear(weaponMuzzle);
02232                 }
02233 
02234                 if (cg.renderingThirdPerson)
02235                 {
02236                         VectorCopy( pEnt->lerpOrigin, gunpoint );
02237                         AngleVectors( pEnt->lerpAngles, forward, right, NULL );
02238                 }
02239                 else
02240                 {
02241                         VectorCopy( cg.refdef.vieworg, gunpoint );
02242                         AngleVectors( cg.refdef.viewangles, forward, right, NULL );
02243                 }
02244 
02245                 if (weapontype == WP_EMPLACED_GUN && cg.snap->ps.emplacedIndex)
02246                 {
02247                         centity_t *gunEnt = &cg_entities[cg.snap->ps.emplacedIndex];
02248 
02249                         if (gunEnt)
02250                         {
02251                                 vec3_t pitchConstraint;
02252 
02253                                 VectorCopy(gunEnt->lerpOrigin, gunpoint);
02254                                 gunpoint[2] += 46;
02255 
02256                                 if (cg.renderingThirdPerson)
02257                                 {
02258                                         VectorCopy(pEnt->lerpAngles, pitchConstraint);
02259                                 }
02260                                 else
02261                                 {
02262                                         VectorCopy(cg.refdef.viewangles, pitchConstraint);
02263                                 }
02264 
02265                                 if (pitchConstraint[PITCH] > 40)
02266                                 {
02267                                         pitchConstraint[PITCH] = 40;
02268                                 }
02269                                 AngleVectors( pitchConstraint, forward, right, NULL );
02270                         }
02271                 }
02272 
02273                 VectorCopy(gunpoint, muzzle);
02274 
02275                 VectorMA(muzzle, weaponMuzzle[0], forward, muzzle);
02276                 VectorMA(muzzle, weaponMuzzle[1], right, muzzle);
02277 
02278                 if (weapontype == WP_EMPLACED_GUN && cg.snap->ps.emplacedIndex)
02279                 {
02280                         //Do nothing
02281                 }
02282                 else if (cg.renderingThirdPerson)
02283                 {
02284                         muzzle[2] += cg.snap->ps.viewheight + weaponMuzzle[2];
02285                 }
02286                 else
02287                 {
02288                         muzzle[2] += weaponMuzzle[2];
02289                 }
02290 
02291                 return qtrue;
02292         }
02293 
02294         cent = &cg_entities[entityNum];
02295         if ( !cent->currentValid ) {
02296                 return qfalse;
02297         }
02298 
02299         VectorCopy( cent->currentState.pos.trBase, muzzle );
02300 
02301         AngleVectors( cent->currentState.apos.trBase, forward, NULL, NULL );
02302         anim = cent->currentState.legsAnim;
02303         if ( anim == BOTH_CROUCH1WALK || anim == BOTH_CROUCH1IDLE ) {
02304                 muzzle[2] += CROUCH_VIEWHEIGHT;
02305         } else {
02306                 muzzle[2] += DEFAULT_VIEWHEIGHT;
02307         }
02308 
02309         VectorMA( muzzle, 14, forward, muzzle );
02310 
02311         return qtrue;
02312 
02313 }
02314 
02315 
02316 
02317 /*
02318 Ghoul2 Insert Start
02319 */
02320 
02321 // create one instance of all the weapons we are going to use so we can just copy this info into each clients gun ghoul2 object in fast way
02322 static void *g2WeaponInstances[MAX_WEAPONS];
02323 
02324 void CG_InitG2Weapons(void)
02325 {
02326         int i = 0;
02327         gitem_t         *item;
02328         memset(g2WeaponInstances, 0, sizeof(g2WeaponInstances));
02329         for ( item = bg_itemlist + 1 ; item->classname ; item++ ) 
02330         {
02331                 if ( item->giType == IT_WEAPON )
02332                 {
02333                         assert(item->giTag < MAX_WEAPONS);
02334 
02335                         // initialise model
02336                         trap_G2API_InitGhoul2Model(&g2WeaponInstances[/*i*/item->giTag], item->world_model[0], 0, 0, 0, 0, 0);
02337 //                      trap_G2API_InitGhoul2Model(&g2WeaponInstances[i], item->world_model[0],G_ModelIndex( item->world_model[0] ) , 0, 0, 0, 0);
02338                         if (g2WeaponInstances[/*i*/item->giTag])
02339                         {
02340                                 // indicate we will be bolted to model 0 (ie the player) on bolt 0 (always the right hand) when we get copied
02341                                 trap_G2API_SetBoltInfo(g2WeaponInstances[/*i*/item->giTag], 0, 0);
02342                                 // now set up the gun bolt on it
02343                                 if (item->giTag == WP_SABER)
02344                                 {
02345                                         trap_G2API_AddBolt(g2WeaponInstances[/*i*/item->giTag], 0, "*blade1");
02346                                 }
02347                                 else
02348                                 {
02349                                         trap_G2API_AddBolt(g2WeaponInstances[/*i*/item->giTag], 0, "*flash");
02350                                 }
02351                                 i++;
02352                         }
02353                         if (i == MAX_WEAPONS)
02354                         {
02355                                 assert(0);      
02356                                 break;
02357                         }
02358                         
02359                 }
02360         }
02361 }
02362 
02363 // clean out any g2 models we instanciated for copying purposes
02364 void CG_ShutDownG2Weapons(void)
02365 {
02366         int i;
02367         for (i=0; i<MAX_WEAPONS; i++)
02368         {
02369                 trap_G2API_CleanGhoul2Models(&g2WeaponInstances[i]);
02370         }
02371 }
02372 
02373 void *CG_G2WeaponInstance(centity_t *cent, int weapon)
02374 {
02375         clientInfo_t *ci = NULL;
02376 
02377         if (weapon != WP_SABER)
02378         {
02379                 return g2WeaponInstances[weapon];
02380         }
02381 
02382         if (cent->currentState.eType != ET_PLAYER &&
02383                 cent->currentState.eType != ET_NPC)
02384         {
02385                 return g2WeaponInstances[weapon];
02386         }
02387 
02388         if (cent->currentState.eType == ET_NPC)
02389         {
02390                 ci = cent->npcClient;
02391         }
02392         else
02393         {
02394                 ci = &cgs.clientinfo[cent->currentState.number];
02395         }
02396 
02397         if (!ci)
02398         {
02399                 return g2WeaponInstances[weapon];
02400         }
02401 
02402         //Try to return the custom saber instance if we can.
02403         if (ci->saber[0].model[0] &&
02404                 ci->ghoul2Weapons[0])
02405         {
02406                 return ci->ghoul2Weapons[0];
02407         }
02408 
02409         //If no custom then just use the default.
02410         return g2WeaponInstances[weapon];
02411 }
02412 
02413 // what ghoul2 model do we want to copy ?
02414 void CG_CopyG2WeaponInstance(centity_t *cent, int weaponNum, void *toGhoul2)
02415 {
02416         //rww - the -1 is because there is no "weapon" for WP_NONE
02417         assert(weaponNum < MAX_WEAPONS);
02418         if (CG_G2WeaponInstance(cent, weaponNum/*-1*/))
02419         {
02420                 if (weaponNum == WP_SABER)
02421                 {
02422                         clientInfo_t *ci = NULL;
02423 
02424                         if (cent->currentState.eType == ET_NPC)
02425                         {
02426                                 ci = cent->npcClient;
02427                         }
02428                         else
02429                         {
02430                                 ci = &cgs.clientinfo[cent->currentState.number];
02431                         }
02432 
02433                         if (!ci)
02434                         {
02435                                 trap_G2API_CopySpecificGhoul2Model(CG_G2WeaponInstance(cent, weaponNum/*-1*/), 0, toGhoul2, 1); 
02436                         }
02437                         else
02438                         { //Try both the left hand saber and the right hand saber
02439                                 int i = 0;
02440 
02441                                 while (i < MAX_SABERS)
02442                                 {
02443                                         if (ci->saber[i].model[0] &&
02444                                                 ci->ghoul2Weapons[i])
02445                                         {
02446                                                 trap_G2API_CopySpecificGhoul2Model(ci->ghoul2Weapons[i], 0, toGhoul2, i+1); 
02447                                         }
02448                                         else if (ci->ghoul2Weapons[i])
02449                                         { //if the second saber has been removed, then be sure to remove it and free the instance.
02450                                                 qboolean g2HasSecondSaber = trap_G2API_HasGhoul2ModelOnIndex(&(toGhoul2), 2);
02451 
02452                                                 if (g2HasSecondSaber)
02453                                                 { //remove it now since we're switching away from sabers
02454                                                         trap_G2API_RemoveGhoul2Model(&(toGhoul2), 2);
02455                                                 }
02456                                                 trap_G2API_CleanGhoul2Models(&ci->ghoul2Weapons[i]);
02457                                         }
02458 
02459                                         i++;
02460                                 }
02461                         }
02462                 }
02463                 else
02464                 {
02465                         qboolean g2HasSecondSaber = trap_G2API_HasGhoul2ModelOnIndex(&(toGhoul2), 2);
02466 
02467                         if (g2HasSecondSaber)
02468                         { //remove it now since we're switching away from sabers
02469                                 trap_G2API_RemoveGhoul2Model(&(toGhoul2), 2);
02470                         }
02471 
02472                         if (weaponNum == WP_EMPLACED_GUN)
02473                         { //a bit of a hack to remove gun model when using an emplaced weap
02474                                 if (trap_G2API_HasGhoul2ModelOnIndex(&(toGhoul2), 1))
02475                                 {
02476                                         trap_G2API_RemoveGhoul2Model(&(toGhoul2), 1);
02477                                 }
02478                         }
02479                         else if (weaponNum == WP_MELEE)
02480                         { //don't want a weapon on the model for this one
02481                                 if (trap_G2API_HasGhoul2ModelOnIndex(&(toGhoul2), 1))
02482                                 {
02483                                         trap_G2API_RemoveGhoul2Model(&(toGhoul2), 1);
02484                                 }
02485                         }
02486                         else
02487                         {
02488                                 trap_G2API_CopySpecificGhoul2Model(CG_G2WeaponInstance(cent, weaponNum/*-1*/), 0, toGhoul2, 1); 
02489                         }
02490                 }
02491         }
02492 }
02493 
02494 void CG_CheckPlayerG2Weapons(playerState_t *ps, centity_t *cent) 
02495 {
02496         if (!ps)
02497         {
02498                 assert(0);
02499                 return;
02500         }
02501 
02502         if (ps->pm_flags & PMF_FOLLOW)
02503         {
02504                 return;
02505         }
02506 
02507         if (cent->currentState.eType == ET_NPC)
02508         {
02509                 assert(0);
02510                 return;
02511         }
02512 
02513         // should we change the gun model on this player?
02514         if (cent->currentState.saberInFlight)
02515         {
02516                 cent->ghoul2weapon = CG_G2WeaponInstance(cent, WP_SABER);
02517         }
02518 
02519         if (cent->currentState.eFlags & EF_DEAD)
02520         { //no updating weapons when dead
02521                 cent->ghoul2weapon = NULL;
02522                 return;
02523         }
02524 
02525         if (cent->torsoBolt)
02526         { //got our limb cut off, no updating weapons until it's restored
02527                 cent->ghoul2weapon = NULL;
02528                 return;
02529         }
02530 
02531         if (cgs.clientinfo[ps->clientNum].team == TEAM_SPECTATOR ||
02532                 ps->persistant[PERS_TEAM] == TEAM_SPECTATOR)
02533         {
02534                 cent->ghoul2weapon = cg_entities[ps->clientNum].ghoul2weapon = NULL;
02535                 cent->weapon = cg_entities[ps->clientNum].weapon = 0;
02536                 return;
02537         }
02538 
02539         if (cent->ghoul2 && cent->ghoul2weapon != CG_G2WeaponInstance(cent, ps->weapon) &&
02540                 ps->clientNum == cent->currentState.number) //don't want spectator mode forcing one client's weapon instance over another's
02541         {
02542                 CG_CopyG2WeaponInstance(cent, ps->weapon, cent->ghoul2);
02543                 cent->ghoul2weapon = CG_G2WeaponInstance(cent, ps->weapon);
02544                 if (cent->weapon == WP_SABER && cent->weapon != ps->weapon && !ps->saberHolstered)
02545                 { //switching away from the saber
02546                         //trap_S_StartSound(cent->lerpOrigin, cent->currentState.number, CHAN_AUTO, trap_S_RegisterSound( "sound/weapons/saber/saberoffquick.wav" ));
02547                         if (cgs.clientinfo[ps->clientNum].saber[0].soundOff && !ps->saberHolstered)
02548                         {
02549                                 trap_S_StartSound(cent->lerpOrigin, cent->currentState.number, CHAN_AUTO, cgs.clientinfo[ps->clientNum].saber[0].soundOff);
02550                         }
02551 
02552                         if (cgs.clientinfo[ps->clientNum].saber[1].soundOff &&
02553                                 cgs.clientinfo[ps->clientNum].saber[1].model[0] &&
02554                                 !ps->saberHolstered)
02555                         {
02556                                 trap_S_StartSound(cent->lerpOrigin, cent->currentState.number, CHAN_AUTO, cgs.clientinfo[ps->clientNum].saber[1].soundOff);
02557                         }
02558                 }
02559                 else if (ps->weapon == WP_SABER && cent->weapon != ps->weapon && !cent->saberWasInFlight)
02560                 { //switching to the saber
02561                         //trap_S_StartSound(cent->lerpOrigin, cent->currentState.number, CHAN_AUTO, trap_S_RegisterSound( "sound/weapons/saber/saberon.wav" ));
02562                         if (cgs.clientinfo[ps->clientNum].saber[0].soundOn)
02563                         {
02564                                 trap_S_StartSound(cent->lerpOrigin, cent->currentState.number, CHAN_AUTO, cgs.clientinfo[ps->clientNum].saber[0].soundOn);
02565                         }
02566 
02567                         if (cgs.clientinfo[ps->clientNum].saber[1].soundOn)
02568                         {
02569                                 trap_S_StartSound(cent->lerpOrigin, cent->currentState.number, CHAN_AUTO, cgs.clientinfo[ps->clientNum].saber[1].soundOn);
02570                         }
02571 
02572                         BG_SI_SetDesiredLength(&cgs.clientinfo[ps->clientNum].saber[0], 0, -1);
02573                         BG_SI_SetDesiredLength(&cgs.clientinfo[ps->clientNum].saber[1], 0, -1);
02574                 }
02575                 cent->weapon = ps->weapon;
02576         }
02577 }
02578 
02579 
02580 /*
02581 Ghoul2 Insert End
02582 */