codemp/cgame/cg_event.c

Go to the documentation of this file.
00001 // Copyright (C) 1999-2000 Id Software, Inc.
00002 //
00003 // cg_event.c -- handle entity events at snapshot or playerstate transitions
00004 
00005 #include "cg_local.h"
00006 #include "fx_local.h"
00007 #include "../ui/ui_shared.h"
00008 #include "../ui/ui_public.h"
00009 
00010 // for the voice chats
00011 #include "../../ui/menudef.h"
00012 
00013 #include "../ghoul2/G2.h"
00014 //==========================================================================
00015 
00016 extern qboolean WP_SaberBladeUseSecondBladeStyle( saberInfo_t *saber, int bladeNum );
00017 extern qboolean CG_VehicleWeaponImpact( centity_t *cent );
00018 extern qboolean CG_InFighter( void );
00019 extern qboolean CG_InATST( void );
00020 extern int cg_saberFlashTime;
00021 extern vec3_t cg_saberFlashPos;
00022 extern char *showPowersName[];
00023 
00024 extern int cg_siegeDeathTime;
00025 extern int cg_siegeDeathDelay;
00026 extern int cg_vehicleAmmoWarning;
00027 extern int cg_vehicleAmmoWarningTime;
00028 
00029 //I know, not siege, but...
00030 typedef enum
00031 {
00032         TAUNT_TAUNT = 0,
00033         TAUNT_BOW,
00034         TAUNT_MEDITATE,
00035         TAUNT_FLOURISH,
00036         TAUNT_GLOAT
00037 };
00038 /*
00039 ===================
00040 CG_PlaceString
00041 
00042 Also called by scoreboard drawing
00043 ===================
00044 */
00045 const char      *CG_PlaceString( int rank ) {
00046         static char     str[64];
00047         char    *s, *t;
00048         // number extenstions, eg 1st, 2nd, 3rd, 4th etc.
00049         // note that the rules are different for french, but by changing the required strip strings they seem to work
00050         char sST[10];
00051         char sND[10];
00052         char sRD[10];
00053         char sTH[10];
00054         char sTiedFor[64];      // german is much longer, super safe...
00055 
00056         trap_SP_GetStringTextString("MP_INGAME_NUMBER_ST",sST, sizeof(sST) );
00057         trap_SP_GetStringTextString("MP_INGAME_NUMBER_ND",sND, sizeof(sND) );
00058         trap_SP_GetStringTextString("MP_INGAME_NUMBER_RD",sRD, sizeof(sRD) );
00059         trap_SP_GetStringTextString("MP_INGAME_NUMBER_TH",sTH, sizeof(sTH) );
00060         trap_SP_GetStringTextString("MP_INGAME_TIED_FOR" ,sTiedFor,sizeof(sTiedFor) );
00061         strcat(sTiedFor," ");   // save worrying about translators adding spaces or not
00062 
00063         if ( rank & RANK_TIED_FLAG ) {
00064                 rank &= ~RANK_TIED_FLAG;
00065                 t = sTiedFor;//"Tied for ";
00066         } else {
00067                 t = "";
00068         }
00069 
00070         if ( rank == 1 ) {
00071                 s = va("1%s",sST);//S_COLOR_BLUE "1st" S_COLOR_WHITE;           // draw in blue
00072         } else if ( rank == 2 ) {
00073                 s = va("2%s",sND);//S_COLOR_RED "2nd" S_COLOR_WHITE;            // draw in red
00074         } else if ( rank == 3 ) {
00075                 s = va("3%s",sRD);//S_COLOR_YELLOW "3rd" S_COLOR_WHITE;         // draw in yellow
00076         } else if ( rank == 11 ) {
00077                 s = va("11%s",sTH);
00078         } else if ( rank == 12 ) {
00079                 s = va("12%s",sTH);
00080         } else if ( rank == 13 ) {
00081                 s = va("13%s",sTH);
00082         } else if ( rank % 10 == 1 ) {
00083                 s = va("%i%s", rank,sST);
00084         } else if ( rank % 10 == 2 ) {
00085                 s = va("%i%s", rank,sND);
00086         } else if ( rank % 10 == 3 ) {
00087                 s = va("%i%s", rank,sRD);
00088         } else {
00089                 s = va("%i%s", rank,sTH);
00090         }
00091 
00092         Com_sprintf( str, sizeof( str ), "%s%s", t, s );
00093         return str;
00094 }
00095 
00096 qboolean CG_ThereIsAMaster(void);
00097 
00098 /*
00099 =============
00100 CG_Obituary
00101 =============
00102 */
00103 static void CG_Obituary( entityState_t *ent ) {
00104         int                     mod;
00105         int                     target, attacker;
00106         char            *message;
00107         const char      *targetInfo;
00108         const char      *attackerInfo;
00109         char            targetName[32];
00110         char            attackerName[32];
00111         gender_t        gender;
00112         clientInfo_t    *ci;
00113 
00114 
00115         target = ent->otherEntityNum;
00116         attacker = ent->otherEntityNum2;
00117         mod = ent->eventParm;
00118 
00119         if ( target < 0 || target >= MAX_CLIENTS ) {
00120                 CG_Error( "CG_Obituary: target out of range" );
00121         }
00122         ci = &cgs.clientinfo[target];
00123 
00124         if ( attacker < 0 || attacker >= MAX_CLIENTS ) {
00125                 attacker = ENTITYNUM_WORLD;
00126                 attackerInfo = NULL;
00127         } else {
00128                 attackerInfo = CG_ConfigString( CS_PLAYERS + attacker );
00129         }
00130 
00131         targetInfo = CG_ConfigString( CS_PLAYERS + target );
00132         if ( !targetInfo ) {
00133                 return;
00134         }
00135         Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof(targetName) - 2);
00136         strcat( targetName, S_COLOR_WHITE );
00137 
00138         // check for single client messages
00139 
00140         switch( mod ) {
00141         case MOD_SUICIDE:
00142         case MOD_FALLING:
00143         case MOD_CRUSH:
00144         case MOD_WATER:
00145         case MOD_SLIME:
00146         case MOD_LAVA:
00147         case MOD_TRIGGER_HURT:
00148                 message = "DIED_GENERIC";
00149                 break;
00150         case MOD_TARGET_LASER:
00151                 message = "DIED_LASER";
00152                 break;
00153         default:
00154                 message = NULL;
00155                 break;
00156         }
00157 
00158         // Attacker killed themselves.  Ridicule them for it.
00159         if (attacker == target) {
00160                 gender = ci->gender;
00161                 switch (mod) {
00162                 case MOD_BRYAR_PISTOL:
00163                 case MOD_BRYAR_PISTOL_ALT:
00164                 case MOD_BLASTER:
00165                 case MOD_TURBLAST:
00166                 case MOD_DISRUPTOR:
00167                 case MOD_DISRUPTOR_SPLASH:
00168                 case MOD_DISRUPTOR_SNIPER:
00169                 case MOD_BOWCASTER:
00170                 case MOD_REPEATER:
00171                 case MOD_REPEATER_ALT:
00172                 case MOD_FLECHETTE:
00173                         if ( gender == GENDER_FEMALE )
00174                                 message = "SUICIDE_SHOT_FEMALE";
00175                         else if ( gender == GENDER_NEUTER )
00176                                 message = "SUICIDE_SHOT_GENDERLESS";
00177                         else
00178                                 message = "SUICIDE_SHOT_MALE";
00179                         break;
00180                 case MOD_REPEATER_ALT_SPLASH:
00181                 case MOD_FLECHETTE_ALT_SPLASH:
00182                 case MOD_ROCKET:
00183                 case MOD_ROCKET_SPLASH:
00184                 case MOD_ROCKET_HOMING:
00185                 case MOD_ROCKET_HOMING_SPLASH:
00186                 case MOD_THERMAL:
00187                 case MOD_THERMAL_SPLASH:
00188                 case MOD_TRIP_MINE_SPLASH:
00189                 case MOD_TIMED_MINE_SPLASH:
00190                 case MOD_DET_PACK_SPLASH:
00191                 case MOD_VEHICLE:
00192                 case MOD_CONC:
00193                 case MOD_CONC_ALT:
00194                         if ( gender == GENDER_FEMALE )
00195                                 message = "SUICIDE_EXPLOSIVES_FEMALE";
00196                         else if ( gender == GENDER_NEUTER )
00197                                 message = "SUICIDE_EXPLOSIVES_GENDERLESS";
00198                         else
00199                                 message = "SUICIDE_EXPLOSIVES_MALE";
00200                         break;
00201                 case MOD_DEMP2:
00202                         if ( gender == GENDER_FEMALE )
00203                                 message = "SUICIDE_ELECTROCUTED_FEMALE";
00204                         else if ( gender == GENDER_NEUTER )
00205                                 message = "SUICIDE_ELECTROCUTED_GENDERLESS";
00206                         else
00207                                 message = "SUICIDE_ELECTROCUTED_MALE";
00208                         break;
00209                 case MOD_FALLING:
00210                         if ( gender == GENDER_FEMALE )
00211                                 message = "SUICIDE_FALLDEATH_FEMALE";
00212                         else if ( gender == GENDER_NEUTER )
00213                                 message = "SUICIDE_FALLDEATH_GENDERLESS";
00214                         else
00215                                 message = "SUICIDE_FALLDEATH_MALE";
00216                         break;
00217                 default:
00218                         if ( gender == GENDER_FEMALE )
00219                                 message = "SUICIDE_GENERICDEATH_FEMALE";
00220                         else if ( gender == GENDER_NEUTER )
00221                                 message = "SUICIDE_GENERICDEATH_GENDERLESS";
00222                         else
00223                                 message = "SUICIDE_GENERICDEATH_MALE";
00224                         break;
00225                 }
00226         }
00227 
00228         if (target != attacker && target < MAX_CLIENTS && attacker < MAX_CLIENTS)
00229         {
00230                 goto clientkilled;
00231         }
00232 
00233         if (message) {
00234                 gender = ci->gender;
00235 
00236                 if (!message[0])
00237                 {
00238                         if ( gender == GENDER_FEMALE )
00239                                 message = "SUICIDE_GENERICDEATH_FEMALE";
00240                         else if ( gender == GENDER_NEUTER )
00241                                 message = "SUICIDE_GENERICDEATH_GENDERLESS";
00242                         else
00243                                 message = "SUICIDE_GENERICDEATH_MALE";
00244                 }
00245                 message = (char *)CG_GetStringEdString("MP_INGAME", message);
00246 
00247                 CG_Printf( "%s %s\n", targetName, message);
00248                 return;
00249         }
00250 
00251 clientkilled:
00252 
00253         // check for kill messages from the current clientNum
00254         if ( attacker == cg.snap->ps.clientNum ) {
00255                 char    *s;
00256 
00257                 if ( cgs.gametype < GT_TEAM && cgs.gametype != GT_DUEL && cgs.gametype != GT_POWERDUEL ) {
00258                         if (cgs.gametype == GT_JEDIMASTER &&
00259                                 attacker < MAX_CLIENTS &&
00260                                 !ent->isJediMaster &&
00261                                 !cg.snap->ps.isJediMaster &&
00262                                 CG_ThereIsAMaster())
00263                         {
00264                                 char part1[512];
00265                                 char part2[512];
00266                                 trap_SP_GetStringTextString("MP_INGAME_KILLED_MESSAGE", part1, sizeof(part1));
00267                                 trap_SP_GetStringTextString("MP_INGAME_JMKILLED_NOTJM", part2, sizeof(part2));
00268                                 s = va("%s %s\n%s\n", part1, targetName, part2);
00269                         }
00270                         else if (cgs.gametype == GT_JEDIMASTER &&
00271                                 attacker < MAX_CLIENTS &&
00272                                 !ent->isJediMaster &&
00273                                 !cg.snap->ps.isJediMaster)
00274                         { //no JM, saber must be out
00275                                 char part1[512];
00276                                 trap_SP_GetStringTextString("MP_INGAME_KILLED_MESSAGE", part1, sizeof(part1));
00277                                 /*
00278                                 kmsg1 = "for 0 points.\nGo for the saber!";
00279                                 strcpy(part2, kmsg1);
00280 
00281                                 s = va("%s %s %s\n", part1, targetName, part2);
00282                                 */
00283                                 s = va("%s %s\n", part1, targetName);
00284                         }
00285                         else if (cgs.gametype == GT_POWERDUEL)
00286                         {
00287                                 s = "";
00288                         }
00289                         else
00290                         {
00291                                 char sPlaceWith[256];
00292                                 char sKilledStr[256];
00293                                 trap_SP_GetStringTextString("MP_INGAME_PLACE_WITH",     sPlaceWith, sizeof(sPlaceWith));
00294                                 trap_SP_GetStringTextString("MP_INGAME_KILLED_MESSAGE", sKilledStr, sizeof(sKilledStr));
00295 
00296                                 s = va("%s %s.\n%s %s %i.", sKilledStr, targetName, 
00297                                         CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ), 
00298                                         sPlaceWith,
00299                                         cg.snap->ps.persistant[PERS_SCORE] );
00300                         }
00301                 } else {
00302                         char sKilledStr[256];
00303                         trap_SP_GetStringTextString("MP_INGAME_KILLED_MESSAGE", sKilledStr, sizeof(sKilledStr));
00304                         s = va("%s %s", sKilledStr, targetName );
00305                 }
00306                 //if (!(cg_singlePlayerActive.integer && cg_cameraOrbit.integer)) {
00307                         CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
00308                 //} 
00309                 // print the text message as well
00310         }
00311 
00312         // check for double client messages
00313         if ( !attackerInfo ) {
00314                 attacker = ENTITYNUM_WORLD;
00315                 strcpy( attackerName, "noname" );
00316         } else {
00317                 Q_strncpyz( attackerName, Info_ValueForKey( attackerInfo, "n" ), sizeof(attackerName) - 2);
00318                 strcat( attackerName, S_COLOR_WHITE );
00319                 // check for kill messages about the current clientNum
00320                 if ( target == cg.snap->ps.clientNum ) {
00321                         Q_strncpyz( cg.killerName, attackerName, sizeof( cg.killerName ) );
00322                 }
00323         }
00324 
00325         if ( attacker != ENTITYNUM_WORLD ) {
00326                 switch (mod) {
00327                 case MOD_STUN_BATON:
00328                         message = "KILLED_STUN";
00329                         break;
00330                 case MOD_MELEE:
00331                         message = "KILLED_MELEE";
00332                         break;
00333                 case MOD_SABER:
00334                         message = "KILLED_SABER";
00335                         break;
00336                 case MOD_BRYAR_PISTOL:
00337                 case MOD_BRYAR_PISTOL_ALT:
00338                         message = "KILLED_BRYAR";
00339                         break;
00340                 case MOD_BLASTER:
00341                         message = "KILLED_BLASTER";
00342                         break;
00343                 case MOD_TURBLAST:
00344                         message = "KILLED_BLASTER";
00345                         break;
00346                 case MOD_DISRUPTOR:
00347                 case MOD_DISRUPTOR_SPLASH:
00348                         message = "KILLED_DISRUPTOR";
00349                         break;
00350                 case MOD_DISRUPTOR_SNIPER:
00351                         message = "KILLED_DISRUPTORSNIPE";
00352                         break;
00353                 case MOD_BOWCASTER:
00354                         message = "KILLED_BOWCASTER";
00355                         break;
00356                 case MOD_REPEATER:
00357                         message = "KILLED_REPEATER";
00358                         break;
00359                 case MOD_REPEATER_ALT:
00360                 case MOD_REPEATER_ALT_SPLASH:
00361                         message = "KILLED_REPEATERALT";
00362                         break;
00363                 case MOD_DEMP2:
00364                 case MOD_DEMP2_ALT:
00365                         message = "KILLED_DEMP2";
00366                         break;
00367                 case MOD_FLECHETTE:
00368                         message = "KILLED_FLECHETTE";
00369                         break;
00370                 case MOD_FLECHETTE_ALT_SPLASH:
00371                         message = "KILLED_FLECHETTE_MINE";
00372                         break;
00373                 case MOD_ROCKET:
00374                 case MOD_ROCKET_SPLASH:
00375                         message = "KILLED_ROCKET";
00376                         break;
00377                 case MOD_ROCKET_HOMING:
00378                 case MOD_ROCKET_HOMING_SPLASH:
00379                         message = "KILLED_ROCKET_HOMING";
00380                         break;
00381                 case MOD_THERMAL:
00382                 case MOD_THERMAL_SPLASH:
00383                         message = "KILLED_THERMAL";
00384                         break;
00385                 case MOD_TRIP_MINE_SPLASH:
00386                         message = "KILLED_TRIPMINE";
00387                         break;
00388                 case MOD_TIMED_MINE_SPLASH:
00389                         message = "KILLED_TRIPMINE_TIMED";
00390                         break;
00391                 case MOD_DET_PACK_SPLASH:
00392                         message = "KILLED_DETPACK";
00393                         break;
00394                 case MOD_VEHICLE:
00395                 case MOD_CONC:
00396                 case MOD_CONC_ALT:
00397                         message = "KILLED_GENERIC";
00398                         break;
00399                 case MOD_FORCE_DARK:
00400                         message = "KILLED_DARKFORCE";
00401                         break;
00402                 case MOD_SENTRY:
00403                         message = "KILLED_SENTRY";
00404                         break;
00405                 case MOD_TELEFRAG:
00406                         message = "KILLED_TELEFRAG";
00407                         break;
00408                 case MOD_CRUSH:
00409                         message = "KILLED_GENERIC";//"KILLED_FORCETOSS";
00410                         break;
00411                 case MOD_FALLING:
00412                         message = "KILLED_FORCETOSS";
00413                         break;
00414                 case MOD_TRIGGER_HURT:
00415                         message = "KILLED_GENERIC";//"KILLED_FORCETOSS";
00416                         break;
00417                 default:
00418                         message = "KILLED_GENERIC";
00419                         break;
00420                 }
00421 
00422                 if (message) {
00423                         message = (char *)CG_GetStringEdString("MP_INGAME", message);
00424 
00425                         CG_Printf( "%s %s %s\n", 
00426                                 targetName, message, attackerName);
00427                         return;
00428                 }
00429         }
00430 
00431         // we don't know what it was
00432         CG_Printf( "%s %s\n", targetName, (char *)CG_GetStringEdString("MP_INGAME", "DIED_GENERIC") );
00433 }
00434 
00435 //==========================================================================
00436 
00437 void CG_ToggleBinoculars(centity_t *cent, int forceZoom)
00438 {
00439         if (cent->currentState.number != cg.snap->ps.clientNum)
00440         {
00441                 return;
00442         }
00443 
00444         if (cg.snap->ps.weaponstate != WEAPON_READY)
00445         { //So we can't fool it and reactivate while switching to the saber or something.
00446                 return;
00447         }
00448 
00449         /*
00450         if (cg.snap->ps.weapon == WP_SABER)
00451         { //No.
00452                 return;
00453         }
00454         */
00455 
00456         if (forceZoom)
00457         {
00458                 if (forceZoom == 2)
00459                 {
00460                         cg.snap->ps.zoomMode = 0;
00461                 }
00462                 else if (forceZoom == 1)
00463                 {
00464                         cg.snap->ps.zoomMode = 2;
00465                 }
00466         }
00467 
00468         if (cg.snap->ps.zoomMode == 0)
00469         {
00470                 trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.media.zoomStart );
00471         }
00472         else if (cg.snap->ps.zoomMode == 2)
00473         {
00474                 trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.media.zoomEnd );
00475         }
00476 }
00477 
00478 //set the local timing bar
00479 extern int cg_genericTimerBar;
00480 extern int cg_genericTimerDur;
00481 extern vec4_t cg_genericTimerColor;
00482 void CG_LocalTimingBar(int startTime, int duration)
00483 {
00484     cg_genericTimerBar = startTime + duration;
00485         cg_genericTimerDur = duration;
00486 
00487         cg_genericTimerColor[0] = 1.0f;
00488         cg_genericTimerColor[1] = 1.0f;
00489         cg_genericTimerColor[2] = 0.0f;
00490         cg_genericTimerColor[3] = 1.0f;
00491 }
00492 
00493 /*
00494 ===============
00495 CG_UseItem
00496 ===============
00497 */
00498 static void CG_UseItem( centity_t *cent ) {
00499         clientInfo_t *ci;
00500         int                     itemNum, clientNum;
00501         gitem_t         *item;
00502         entityState_t *es;
00503 
00504         es = &cent->currentState;
00505         
00506         itemNum = (es->event & ~EV_EVENT_BITS) - EV_USE_ITEM0;
00507         if ( itemNum < 0 || itemNum > HI_NUM_HOLDABLE ) {
00508                 itemNum = 0;
00509         }
00510 
00511         // print a message if the local player
00512         if ( es->number == cg.snap->ps.clientNum ) {
00513                 if ( !itemNum ) {
00514                         //CG_CenterPrint( "No item to use", SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
00515                 } else {
00516                         item = BG_FindItemForHoldable( itemNum );
00517                 }
00518         }
00519 
00520         switch ( itemNum ) {
00521         default:
00522         case HI_NONE:
00523                 //trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useNothingSound );
00524                 break;
00525 
00526         case HI_BINOCULARS:
00527                 CG_ToggleBinoculars(cent, es->eventParm);
00528                 break;
00529 
00530         case HI_SEEKER:
00531                 trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.deploySeeker );
00532                 break;
00533 
00534         case HI_SHIELD:
00535         case HI_SENTRY_GUN:
00536                 break;
00537 
00538 //      case HI_MEDKIT:
00539         case HI_MEDPAC:
00540         case HI_MEDPAC_BIG:
00541                 clientNum = cent->currentState.clientNum;
00542                 if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
00543                         ci = &cgs.clientinfo[ clientNum ];
00544                         ci->medkitUsageTime = cg.time;
00545                 }
00546                 //Different sound for big bacta?
00547                 trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.medkitSound );
00548                 break;
00549         case HI_JETPACK:
00550                 break; //Do something?
00551         case HI_HEALTHDISP:
00552                 //CG_LocalTimingBar(cg.time, TOSS_DEBOUNCE_TIME);
00553                 break;
00554         case HI_AMMODISP:
00555                 //CG_LocalTimingBar(cg.time, TOSS_DEBOUNCE_TIME);
00556                 break;
00557         case HI_EWEB:
00558                 break;
00559         case HI_CLOAK:
00560                 break; //Do something?
00561         }
00562 
00563         if (cg.snap && cg.snap->ps.clientNum == cent->currentState.number && itemNum != HI_BINOCULARS &&
00564                 itemNum != HI_JETPACK && itemNum != HI_HEALTHDISP && itemNum != HI_AMMODISP && itemNum != HI_CLOAK && itemNum != HI_EWEB)
00565         { //if not using binoculars/jetpack/dispensers/cloak, we just used that item up, so switch
00566                 BG_CycleInven(&cg.snap->ps, 1);
00567                 cg.itemSelect = -1; //update the client-side selection display
00568         }
00569 }
00570 
00571 
00572 /*
00573 ================
00574 CG_ItemPickup
00575 
00576 A new item was picked up this frame
00577 ================
00578 */
00579 static void CG_ItemPickup( int itemNum ) {
00580         cg.itemPickup = itemNum;
00581         cg.itemPickupTime = cg.time;
00582         cg.itemPickupBlendTime = cg.time;
00583         // see if it should be the grabbed weapon
00584         if ( cg.snap && bg_itemlist[itemNum].giType == IT_WEAPON ) {
00585 
00586                 // 0 == no switching
00587                 // 1 == automatically switch to best SAFE weapon
00588                 // 2 == automatically switch to best weapon, safe or otherwise
00589                 // 3 == if not saber, automatically switch to best weapon, safe or otherwise
00590 
00591                 if (0 == cg_autoswitch.integer)
00592                 {
00593                         // don't switch
00594                 }
00595                 else if ( cg_autoswitch.integer == 1)
00596                 { //only autoselect if not explosive ("safe")
00597                         if (bg_itemlist[itemNum].giTag != WP_TRIP_MINE &&
00598                                 bg_itemlist[itemNum].giTag != WP_DET_PACK &&
00599                                 bg_itemlist[itemNum].giTag != WP_THERMAL &&
00600                                 bg_itemlist[itemNum].giTag != WP_ROCKET_LAUNCHER &&
00601                                 bg_itemlist[itemNum].giTag > cg.snap->ps.weapon &&
00602                                 cg.snap->ps.weapon != WP_SABER)
00603                         {
00604                                 if (!cg.snap->ps.emplacedIndex)
00605                                 {
00606                                         cg.weaponSelectTime = cg.time;
00607                                 }
00608                                 cg.weaponSelect = bg_itemlist[itemNum].giTag;
00609                         }
00610                 }
00611                 else if ( cg_autoswitch.integer == 2)
00612                 { //autoselect if better
00613                         if (bg_itemlist[itemNum].giTag > cg.snap->ps.weapon &&
00614                                 cg.snap->ps.weapon != WP_SABER)
00615                         {
00616                                 if (!cg.snap->ps.emplacedIndex)
00617                                 {
00618                                         cg.weaponSelectTime = cg.time;
00619                                 }
00620                                 cg.weaponSelect = bg_itemlist[itemNum].giTag;
00621                         }
00622                 }
00623                 /*
00624                 else if ( cg_autoswitch.integer == 3)
00625                 { //autoselect if better and not using the saber as a weapon
00626                         if (bg_itemlist[itemNum].giTag > cg.snap->ps.weapon &&
00627                                 cg.snap->ps.weapon != WP_SABER)
00628                         {
00629                                 if (!cg.snap->ps.emplacedIndex)
00630                                 {
00631                                         cg.weaponSelectTime = cg.time;
00632                                 }
00633                                 cg.weaponSelect = bg_itemlist[itemNum].giTag;
00634                         }
00635                 }
00636                 */
00637                 //No longer required - just not switching ever if using saber
00638         }
00639 
00640         //rww - print pickup messages
00641         if (bg_itemlist[itemNum].classname && bg_itemlist[itemNum].classname[0] &&
00642                 (bg_itemlist[itemNum].giType != IT_TEAM || (bg_itemlist[itemNum].giTag != PW_REDFLAG && bg_itemlist[itemNum].giTag != PW_BLUEFLAG)) )
00643         { //don't print messages for flags, they have their own pickup event broadcasts
00644                 char    text[1024];
00645                 char    upperKey[1024];
00646 
00647                 strcpy(upperKey, bg_itemlist[itemNum].classname);
00648 
00649                 if ( trap_SP_GetStringTextString( va("SP_INGAME_%s",Q_strupr(upperKey)), text, sizeof( text )))
00650                 {
00651                         Com_Printf("%s %s\n", CG_GetStringEdString("MP_INGAME", "PICKUPLINE"), text);
00652                 }
00653                 else
00654                 {
00655                         Com_Printf("%s %s\n", CG_GetStringEdString("MP_INGAME", "PICKUPLINE"), bg_itemlist[itemNum].classname);
00656                 }
00657         }
00658 }
00659 
00660 
00661 /*
00662 ================
00663 CG_PainEvent
00664 
00665 Also called by playerstate transition
00666 ================
00667 */
00668 void CG_PainEvent( centity_t *cent, int health ) {
00669         char    *snd;
00670 
00671         // don't do more than two pain sounds a second
00672         if ( cg.time - cent->pe.painTime < 500 ) {
00673                 return;
00674         }
00675 
00676         if ( health < 25 ) {
00677                 snd = "*pain25.wav";
00678         } else if ( health < 50 ) {
00679                 snd = "*pain50.wav";
00680         } else if ( health < 75 ) {
00681                 snd = "*pain75.wav";
00682         } else {
00683                 snd = "*pain100.wav";
00684         }
00685         trap_S_StartSound( NULL, cent->currentState.number, CHAN_VOICE, 
00686                 CG_CustomSound( cent->currentState.number, snd ) );
00687 
00688         // save pain time for programitic twitch animation
00689         cent->pe.painTime = cg.time;
00690         cent->pe.painDirection  ^= 1;
00691 }
00692 
00693 extern qboolean BG_GetRootSurfNameWithVariant( void *ghoul2, const char *rootSurfName, char *returnSurfName, int returnSize );
00694 void CG_ReattachLimb(centity_t *source)
00695 {
00696         clientInfo_t *ci = NULL;
00697         
00698         if ( source->currentState.number >= MAX_CLIENTS )
00699         {
00700                 ci = source->npcClient;
00701         }
00702         else
00703         {
00704                 ci = &cgs.clientinfo[source->currentState.number];
00705         }
00706         if ( ci )
00707         {//re-apply the skin
00708                 if ( ci->torsoSkin > 0 )
00709                 {
00710                         trap_G2API_SetSkin(source->ghoul2,0,ci->torsoSkin,ci->torsoSkin);
00711                 }
00712         }
00713                 
00714         /*
00715         char *limbName;
00716         char *stubCapName;
00717         int i = G2_MODELPART_HEAD;
00718 
00719         //rww NOTE: Assumes G2_MODELPART_HEAD is first and G2_MODELPART_RLEG is last
00720         while (i <= G2_MODELPART_RLEG)
00721         {
00722                 if (source->torsoBolt & (1 << (i-10)))
00723                 {
00724                         switch (i)
00725                         {
00726                         case G2_MODELPART_HEAD:
00727                                 limbName = "head";
00728                                 stubCapName = "torso_cap_head";
00729                                 break;
00730                         case G2_MODELPART_WAIST:
00731                                 limbName = "torso";
00732                                 stubCapName = "hips_cap_torso";
00733                                 break;
00734                         case G2_MODELPART_LARM:
00735                                 limbName = "l_arm";
00736                                 stubCapName = "torso_cap_l_arm";
00737                                 break;
00738                         case G2_MODELPART_RARM:
00739                                 limbName = "r_arm";
00740                                 stubCapName = "torso_cap_r_arm";
00741                                 break;
00742                         case G2_MODELPART_RHAND:
00743                                 limbName = "r_hand";
00744                                 stubCapName = "r_arm_cap_r_hand";
00745                                 break;
00746                         case G2_MODELPART_LLEG:
00747                                 limbName = "l_leg";
00748                                 stubCapName = "hips_cap_l_leg";
00749                                 break;
00750                         case G2_MODELPART_RLEG:
00751                                 limbName = "r_leg";
00752                                 stubCapName = "hips_cap_r_leg";
00753                                 break;
00754                         default:
00755                                 source->torsoBolt = 0;
00756                                 source->ghoul2weapon = NULL;
00757                                 return;
00758                         }
00759 
00760                         trap_G2API_SetSurfaceOnOff(source->ghoul2, limbName, 0);
00761                         trap_G2API_SetSurfaceOnOff(source->ghoul2, stubCapName, 0x00000100);
00762                 }
00763                 i++;
00764         }
00765         */
00766         source->torsoBolt = 0;
00767 
00768         source->ghoul2weapon = NULL;
00769 }
00770 
00771 const char *CG_TeamName(int team)
00772 {
00773         if (team==TEAM_RED)
00774                 return "RED";
00775         else if (team==TEAM_BLUE)
00776                 return "BLUE";
00777         else if (team==TEAM_SPECTATOR)
00778                 return "SPECTATOR";
00779         return "FREE";
00780 }
00781 
00782 void CG_PrintCTFMessage(clientInfo_t *ci, const char *teamName, int ctfMessage)
00783 {
00784         char printMsg[1024];
00785         char *refName = NULL;
00786         const char *psStringEDString = NULL;
00787 
00788         switch (ctfMessage)
00789         {
00790         case CTFMESSAGE_FRAGGED_FLAG_CARRIER:
00791                 refName = "FRAGGED_FLAG_CARRIER";
00792                 break;
00793         case CTFMESSAGE_FLAG_RETURNED:
00794                 refName = "FLAG_RETURNED";
00795                 break;
00796         case CTFMESSAGE_PLAYER_RETURNED_FLAG:
00797                 refName = "PLAYER_RETURNED_FLAG";
00798                 break;
00799         case CTFMESSAGE_PLAYER_CAPTURED_FLAG:
00800                 refName = "PLAYER_CAPTURED_FLAG";
00801                 break;
00802         case CTFMESSAGE_PLAYER_GOT_FLAG:
00803                 refName = "PLAYER_GOT_FLAG";
00804                 break;
00805         default:
00806                 return;
00807         }
00808 
00809         psStringEDString = CG_GetStringEdString("MP_INGAME", refName);
00810 
00811         if (!psStringEDString || !psStringEDString[0])
00812         {
00813                 return;
00814         }
00815 
00816         if (teamName && teamName[0])
00817         {
00818                 const char *f = strstr(psStringEDString, "%s");
00819 
00820                 if (f)
00821                 {
00822                         int strLen = 0;
00823                         int i = 0;
00824 
00825                         if (ci)
00826                         {
00827                                 Com_sprintf(printMsg, sizeof(printMsg), "%s ", ci->name);
00828                                 strLen = strlen(printMsg);
00829                         }
00830 
00831                         while (psStringEDString[i] && i < 512)
00832                         {
00833                                 if (psStringEDString[i] == '%' &&
00834                                         psStringEDString[i+1] == 's')
00835                                 {
00836                                         printMsg[strLen] = '\0';
00837                                         Q_strcat(printMsg, sizeof(printMsg), teamName);
00838                                         strLen = strlen(printMsg);
00839 
00840                                         i++;
00841                                 }
00842                                 else
00843                                 {
00844                                         printMsg[strLen] = psStringEDString[i];
00845                                         strLen++;
00846                                 }
00847 
00848                                 i++;
00849                         }
00850 
00851                         printMsg[strLen] = '\0';
00852 
00853                         goto doPrint;
00854                 }
00855         }
00856 
00857         if (ci)
00858         {
00859                 Com_sprintf(printMsg, sizeof(printMsg), "%s %s", ci->name, psStringEDString);
00860         }
00861         else
00862         {
00863                 Com_sprintf(printMsg, sizeof(printMsg), "%s", psStringEDString);
00864         }
00865 
00866 doPrint:
00867         Com_Printf("%s\n", printMsg);
00868 }
00869 
00870 void CG_GetCTFMessageEvent(entityState_t *es)
00871 {
00872         int clIndex = es->trickedentindex;
00873         int teamIndex = es->trickedentindex2;
00874         clientInfo_t *ci = NULL;
00875         const char *teamName = NULL;
00876 
00877         if (clIndex < MAX_CLIENTS)
00878         {
00879                 ci = &cgs.clientinfo[clIndex];
00880         }
00881 
00882         if (teamIndex < 50)
00883         {
00884                 teamName = CG_TeamName(teamIndex);
00885         }
00886 
00887         if (!ci)
00888         {
00889                 return;
00890         }
00891 
00892         CG_PrintCTFMessage(ci, teamName, es->eventParm);
00893 }
00894 
00895 #include "../namespace_begin.h"
00896 qboolean BG_InKnockDownOnly( int anim );
00897 #include "../namespace_end.h"
00898 
00899 //JLFRUMBLE
00900 #ifdef _XBOX
00901 extern void FF_XboxDamage(int damage, float xpos);
00902 #endif
00903 
00904 void DoFall(centity_t *cent, entityState_t *es, int clientNum)
00905 {
00906         int delta = es->eventParm;
00907 
00908         if (cent->currentState.eFlags & EF_DEAD)
00909         { //corpses crack into the ground ^_^
00910                 if (delta > 25)
00911                 {
00912                         trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.fallSound );
00913                 }
00914                 else
00915                 {
00916                         trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound( "sound/movers/objects/objectHit.wav" ) );
00917                 }
00918         }
00919         else if (BG_InKnockDownOnly(es->legsAnim))
00920         {
00921                 if (delta > 14)
00922                 {
00923                         trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.fallSound );
00924                 }
00925                 else
00926                 {
00927                         trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound( "sound/movers/objects/objectHit.wav" ) );
00928                 }
00929         }
00930         else if (delta > 50)
00931         {
00932                 trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.fallSound );
00933                 trap_S_StartSound( NULL, cent->currentState.number, CHAN_VOICE, 
00934                         CG_CustomSound( cent->currentState.number, "*land1.wav" ) );
00935                 cent->pe.painTime = cg.time;    // don't play a pain sound right after this
00936         }
00937         else if (delta > 44)
00938         {
00939                 trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.fallSound );
00940                 trap_S_StartSound( NULL, cent->currentState.number, CHAN_VOICE, 
00941                         CG_CustomSound( cent->currentState.number, "*land1.wav" ) );
00942                 cent->pe.painTime = cg.time;    // don't play a pain sound right after this
00943         }
00944         else
00945         {
00946                 trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound );
00947         }
00948         
00949         if ( clientNum == cg.predictedPlayerState.clientNum )
00950         {
00951                 // smooth landing z changes
00952                 cg.landChange = -delta;
00953                 if (cg.landChange > 32)
00954                 {
00955                         cg.landChange = 32;
00956                 }
00957                 if (cg.landChange < -32)
00958                 {
00959                         cg.landChange = -32;
00960                 }
00961                 cg.landTime = cg.time;
00962         }
00963 //JLFRUMBLE
00964 #ifdef _XBOX
00965         if ( cent->playerState)
00966         {
00967 
00968                 if (BG_InKnockDownOnly(es->legsAnim))
00969                 {
00970                         if (delta > 14)
00971                         {
00972                                 FF_XboxDamage(20, 0);
00973                         }
00974                         else
00975                         {
00976                                 FF_XboxDamage(14, 0);
00977                         }
00978                         return;
00979                 }
00980                 if ( delta > 50)
00981                         FF_XboxDamage(50, 0);
00982                 else 
00983                         FF_XboxDamage(delta, 0);
00984 /*              else if (delta > 44)
00985                         FF_XboxDamage(44, 0);
00986                 else 
00987                         FF_XboxDamage(20, 0);
00988 */
00989         }
00990 #endif
00991 
00992 
00993 
00994 }
00995 
00996 int CG_InClientBitflags(entityState_t *ent, int client)
00997 {
00998         int checkIn;
00999         int sub = 0;
01000 
01001         if (client > 47)
01002         {
01003                 checkIn = ent->trickedentindex4;
01004                 sub = 48;
01005         }
01006         else if (client > 31)
01007         {
01008                 checkIn = ent->trickedentindex3;
01009                 sub = 32;
01010         }
01011         else if (client > 15)
01012         {
01013                 checkIn = ent->trickedentindex2;
01014                 sub = 16;
01015         }
01016         else
01017         {
01018                 checkIn = ent->trickedentindex;
01019         }
01020 
01021         if (checkIn & (1 << (client-sub)))
01022         {
01023                 return 1;
01024         }
01025         
01026         return 0;
01027 }
01028 
01029 void CG_PlayDoorLoopSound( centity_t *cent );
01030 void CG_PlayDoorSound( centity_t *cent, int type );
01031 
01032 void CG_TryPlayCustomSound( vec3_t origin, int entityNum, int channel, const char *soundName )
01033 {
01034         sfxHandle_t cSound = CG_CustomSound(entityNum, soundName);
01035 
01036         if (cSound <= 0)
01037         {
01038                 return;
01039         }
01040 
01041         trap_S_StartSound(origin, entityNum, channel, cSound);
01042 }
01043 
01044 void CG_G2MarkEvent(entityState_t *es)
01045 {
01046         //es->origin should be the hit location of the projectile,
01047         //whereas es->origin2 is the predicted position of the
01048         //projectile. (based on the trajectory upon impact) -rww
01049         centity_t *pOwner = &cg_entities[es->otherEntityNum];
01050         vec3_t startPoint;
01051         float   size = 0.0f;
01052         qhandle_t shader = 0;
01053 
01054         if (!pOwner->ghoul2)
01055         { //can't do anything then...
01056                 return;
01057         }
01058 
01059         //es->eventParm being non-0 means to do a special trace check
01060         //first. This will give us an impact right at the surface to
01061         //project the mark on. Typically this is used for radius
01062         //explosions and such, where the source position could be
01063         //way outside of model space.
01064         if (es->eventParm)
01065         {
01066                 trace_t tr;
01067                 int ignore = ENTITYNUM_NONE;
01068 
01069                 CG_G2Trace(&tr, es->origin, NULL, NULL, es->origin2, ignore, MASK_PLAYERSOLID);
01070 
01071                 if (tr.entityNum != es->otherEntityNum)
01072                 { //try again if we hit an ent but not the one we wanted.
01073                         //CG_TestLine(es->origin, es->origin2, 2000, 0x0000ff, 1);
01074                         if (tr.entityNum < ENTITYNUM_WORLD)
01075                         {
01076                                 ignore = tr.entityNum;
01077                                 CG_G2Trace(&tr, es->origin, NULL, NULL, es->origin2, ignore, MASK_PLAYERSOLID);
01078                                 if (tr.entityNum != es->otherEntityNum)
01079                                 { //try extending the trace a bit.. or not
01080                                         /*
01081                                         vec3_t v;
01082 
01083                                         VectorSubtract(es->origin2, es->origin, v);
01084                                         VectorScale(v, 64.0f, v);
01085                                         VectorAdd(es->origin2, v, es->origin2);
01086 
01087                                         CG_G2Trace(&tr, es->origin, NULL, NULL, es->origin2, ignore, MASK_PLAYERSOLID);
01088                                         if (tr.entityNum != es->otherEntityNum)
01089                                         {
01090                                                 return;
01091                                         }
01092                                         */
01093                                         //didn't manage to collide with the desired person. No mark will be placed then.
01094                                         return;
01095                                 }
01096                         }
01097                 }
01098 
01099                 //otherwise we now have a valid starting point.
01100                 VectorCopy(tr.endpos, startPoint);
01101         }
01102         else
01103         {
01104                 VectorCopy(es->origin, startPoint);
01105         }
01106 
01107         if ( (es->eFlags&EF_JETPACK_ACTIVE) )
01108         {// a vehicle weapon, make it a larger size mark
01109                 //OR base this on the size of the thing you hit?
01110                 if ( g_vehWeaponInfo[es->otherEntityNum2].fG2MarkSize )
01111                 {
01112                         size = flrand( 0.6f, 1.4f )*g_vehWeaponInfo[es->otherEntityNum2].fG2MarkSize;
01113                 }
01114                 else
01115                 {       
01116                         size = flrand( 32.0f, 72.0f );
01117                 }
01118                 //specify mark shader in vehWeapon file
01119                 if ( g_vehWeaponInfo[es->otherEntityNum2].iG2MarkShaderHandle )
01120                 {//have one we want to use instead of defaults
01121                         shader = g_vehWeaponInfo[es->otherEntityNum2].iG2MarkShaderHandle;
01122                 }
01123         }
01124         switch(es->weapon)
01125         {
01126         case WP_BRYAR_PISTOL:
01127         case WP_CONCUSSION:
01128         case WP_BRYAR_OLD:
01129         case WP_BLASTER:
01130         case WP_DISRUPTOR:
01131         case WP_BOWCASTER:
01132         case WP_REPEATER:
01133         case WP_TURRET:
01134                 if ( !size )
01135                 {
01136                         size = 4.0f;
01137                 }
01138                 if ( !shader )
01139                 {
01140                         shader = cgs.media.bdecal_bodyburn1;
01141                 }
01142                 CG_AddGhoul2Mark(shader, size, 
01143                         startPoint, es->origin2, es->owner, pOwner->lerpOrigin,
01144                         pOwner->lerpAngles[YAW], pOwner->ghoul2,
01145                         pOwner->modelScale, Q_irand(10000, 20000));
01146                 break;
01147         case WP_ROCKET_LAUNCHER:
01148         case WP_THERMAL:
01149                 if ( !size )
01150                 {
01151                         size = 24.0f;
01152                 }
01153                 if ( !shader )
01154                 {
01155                         shader = cgs.media.bdecal_burn1;
01156                 }
01157                 CG_AddGhoul2Mark(shader, size, 
01158                         startPoint, es->origin2, es->owner, pOwner->lerpOrigin,
01159                         pOwner->lerpAngles[YAW], pOwner->ghoul2,
01160                         pOwner->modelScale, Q_irand(10000, 20000));
01161                 break;
01162                 /*
01163         case WP_FLECHETTE:
01164                 CG_AddGhoul2Mark(cgs.media.bdecal_bodyburn1, flrand(0.5f, 1.0f), 
01165                         startPoint, es->origin2, es->owner, pOwner->lerpOrigin,
01166                         pOwner->lerpAngles[YAW], pOwner->ghoul2,
01167                         pOwner->modelScale);
01168                 break;
01169                 */
01170                 //Issues with small scale?
01171         default:
01172                 break;
01173         }
01174 }
01175 
01176 void CG_CalcVehMuzzle(Vehicle_t *pVeh, centity_t *ent, int muzzleNum)
01177 {
01178         mdxaBone_t boltMatrix;
01179         vec3_t  vehAngles;
01180 
01181         assert(pVeh);
01182 
01183         if (pVeh->m_iMuzzleTime[muzzleNum] == cg.time)
01184         { //already done for this frame, don't need to do it again
01185                 return;
01186         }
01187         //Uh... how about we set this, hunh...?  :)
01188         pVeh->m_iMuzzleTime[muzzleNum] = cg.time;
01189 
01190         VectorCopy( ent->lerpAngles, vehAngles );
01191         if ( pVeh->m_pVehicleInfo )
01192         {
01193                 if (pVeh->m_pVehicleInfo->type == VH_ANIMAL
01194                          ||pVeh->m_pVehicleInfo->type == VH_WALKER)
01195                 {
01196                         vehAngles[PITCH] = vehAngles[ROLL] = 0.0f;
01197                 }
01198                 else if (pVeh->m_pVehicleInfo->type == VH_SPEEDER)
01199                 {
01200                         vehAngles[PITCH] = 0.0f;
01201                 }
01202         }
01203         trap_G2API_GetBoltMatrix_NoRecNoRot(ent->ghoul2, 0, pVeh->m_iMuzzleTag[muzzleNum], &boltMatrix, vehAngles,
01204                 ent->lerpOrigin, cg.time, NULL, ent->modelScale);
01205         BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, pVeh->m_vMuzzlePos[muzzleNum]);
01206         BG_GiveMeVectorFromMatrix(&boltMatrix, NEGATIVE_Y, pVeh->m_vMuzzleDir[muzzleNum]);
01207 }
01208 
01209 //corresponds to G_VehMuzzleFireFX -rww
01210 void CG_VehMuzzleFireFX(centity_t *veh, entityState_t *broadcaster)
01211 {
01212         Vehicle_t *pVeh = veh->m_pVehicle;
01213         int curMuz = 0, muzFX = 0;
01214 
01215         if (!pVeh || !veh->ghoul2)
01216         {
01217                 return;
01218         }
01219 
01220         for ( curMuz = 0; curMuz < MAX_VEHICLE_MUZZLES; curMuz++ )
01221         {//go through all muzzles and 
01222                 if ( pVeh->m_iMuzzleTag[curMuz] != -1//valid muzzle bolt
01223                         && (broadcaster->trickedentindex&(1<<curMuz)) )//fired
01224                 {//this muzzle fired
01225                         muzFX = 0;
01226                         if ( pVeh->m_pVehicleInfo->weapMuzzle[curMuz] == 0 )
01227                         {//no weaopon for this muzzle?  check turrets
01228                                 int i, j;
01229                                 for ( i = 0; i < MAX_VEHICLE_TURRETS; i++ )
01230                                 {
01231                                         for ( j = 0; j < MAX_VEHICLE_TURRETS; j++ )
01232                                         {
01233                                                 if ( pVeh->m_pVehicleInfo->turret[i].iMuzzle[j]-1 == curMuz )
01234                                                 {//this muzzle belongs to this turret
01235                                                         muzFX = g_vehWeaponInfo[pVeh->m_pVehicleInfo->turret[i].iWeapon].iMuzzleFX;
01236                                                         break;
01237                                                 }
01238                                         }
01239                                 }
01240                         }
01241                         else
01242                         {
01243                                 muzFX = g_vehWeaponInfo[pVeh->m_pVehicleInfo->weapMuzzle[curMuz]].iMuzzleFX;
01244                         }
01245                         if ( muzFX )
01246                         {
01247                                 //CG_CalcVehMuzzle(pVeh, veh, curMuz);
01248                                 //trap_FX_PlayEffectID(muzFX, pVeh->m_vMuzzlePos[curMuz], pVeh->m_vMuzzleDir[curMuz], -1, -1);
01249                                 trap_FX_PlayBoltedEffectID(muzFX, veh->currentState.origin, veh->ghoul2, pVeh->m_iMuzzleTag[curMuz], veh->currentState.number, 0, 0, qtrue);
01250                         }
01251                 }
01252         }
01253 }
01254 
01255 const char      *cg_stringEdVoiceChatTable[MAX_CUSTOM_SIEGE_SOUNDS] = 
01256 {
01257         "VC_ATT",//"*att_attack",
01258         "VC_ATT_PRIMARY",//"*att_primary",
01259         "VC_ATT_SECONDARY",//"*att_second",
01260         "VC_DEF_GUNS",//"*def_guns",
01261         "VC_DEF_POSITION",//"*def_position",
01262         "VC_DEF_PRIMARY",//"*def_primary",
01263         "VC_DEF_SECONDARY",//"*def_second",
01264         "VC_REPLY_COMING",//"*reply_coming",
01265         "VC_REPLY_GO",//"*reply_go",
01266         "VC_REPLY_NO",//"*reply_no",
01267         "VC_REPLY_STAY",//"*reply_stay",
01268         "VC_REPLY_YES",//"*reply_yes",
01269         "VC_REQ_ASSIST",//"*req_assist",
01270         "VC_REQ_DEMO",//"*req_demo",
01271         "VC_REQ_HVY",//"*req_hvy",
01272         "VC_REQ_MEDIC",//"*req_medic",
01273         "VC_REQ_SUPPLY",//"*req_sup",
01274         "VC_REQ_TECH",//"*req_tech",
01275         "VC_SPOT_AIR",//"*spot_air",
01276         "VC_SPOT_DEF",//"*spot_defenses",
01277         "VC_SPOT_EMPLACED",//"*spot_emplaced",
01278         "VC_SPOT_SNIPER",//"*spot_sniper",
01279         "VC_SPOT_TROOP",//"*spot_troops",
01280         "VC_TAC_COVER",//"*tac_cover",
01281         "VC_TAC_FALLBACK",//"*tac_fallback",
01282         "VC_TAC_FOLLOW",//"*tac_follow",
01283         "VC_TAC_HOLD",//"*tac_hold",
01284         "VC_TAC_SPLIT",//"*tac_split",
01285         "VC_TAC_TOGETHER",//"*tac_together",
01286         NULL
01287 };
01288 
01289 //stupid way of figuring out what string to use for voice chats
01290 const