00001
00002
00003
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
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
00030 typedef enum
00031 {
00032 TAUNT_TAUNT = 0,
00033 TAUNT_BOW,
00034 TAUNT_MEDITATE,
00035 TAUNT_FLOURISH,
00036 TAUNT_GLOAT
00037 };
00038
00039
00040
00041
00042
00043
00044
00045 const char *CG_PlaceString( int rank ) {
00046 static char str[64];
00047 char *s, *t;
00048
00049
00050 char sST[10];
00051 char sND[10];
00052 char sRD[10];
00053 char sTH[10];
00054 char sTiedFor[64];
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," ");
00062
00063 if ( rank & RANK_TIED_FLAG ) {
00064 rank &= ~RANK_TIED_FLAG;
00065 t = sTiedFor;
00066 } else {
00067 t = "";
00068 }
00069
00070 if ( rank == 1 ) {
00071 s = va("1%s",sST);
00072 } else if ( rank == 2 ) {
00073 s = va("2%s",sND);
00074 } else if ( rank == 3 ) {
00075 s = va("3%s",sRD);
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
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
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
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
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 {
00275 char part1[512];
00276 trap_SP_GetStringTextString("MP_INGAME_KILLED_MESSAGE", part1, sizeof(part1));
00277
00278
00279
00280
00281
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
00307 CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
00308
00309
00310 }
00311
00312
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
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";
00410 break;
00411 case MOD_FALLING:
00412 message = "KILLED_FORCETOSS";
00413 break;
00414 case MOD_TRIGGER_HURT:
00415 message = "KILLED_GENERIC";
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
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 {
00446 return;
00447 }
00448
00449
00450
00451
00452
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
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
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 = ¢->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
00512 if ( es->number == cg.snap->ps.clientNum ) {
00513 if ( !itemNum ) {
00514
00515 } else {
00516 item = BG_FindItemForHoldable( itemNum );
00517 }
00518 }
00519
00520 switch ( itemNum ) {
00521 default:
00522 case HI_NONE:
00523
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
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
00547 trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.medkitSound );
00548 break;
00549 case HI_JETPACK:
00550 break;
00551 case HI_HEALTHDISP:
00552
00553 break;
00554 case HI_AMMODISP:
00555
00556 break;
00557 case HI_EWEB:
00558 break;
00559 case HI_CLOAK:
00560 break;
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 {
00566 BG_CycleInven(&cg.snap->ps, 1);
00567 cg.itemSelect = -1;
00568 }
00569 }
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579 static void CG_ItemPickup( int itemNum ) {
00580 cg.itemPickup = itemNum;
00581 cg.itemPickupTime = cg.time;
00582 cg.itemPickupBlendTime = cg.time;
00583
00584 if ( cg.snap && bg_itemlist[itemNum].giType == IT_WEAPON ) {
00585
00586
00587
00588
00589
00590
00591 if (0 == cg_autoswitch.integer)
00592 {
00593
00594 }
00595 else if ( cg_autoswitch.integer == 1)
00596 {
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 {
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
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638 }
00639
00640
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 {
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
00664
00665
00666
00667
00668 void CG_PainEvent( centity_t *cent, int health ) {
00669 char *snd;
00670
00671
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
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 {
00708 if ( ci->torsoSkin > 0 )
00709 {
00710 trap_G2API_SetSkin(source->ghoul2,0,ci->torsoSkin,ci->torsoSkin);
00711 }
00712 }
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
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
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 {
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;
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;
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
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
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
00985
00986
00987
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
01047
01048
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 {
01056 return;
01057 }
01058
01059
01060
01061
01062
01063
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 {
01073
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 {
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094 return;
01095 }
01096 }
01097 }
01098
01099
01100 VectorCopy(tr.endpos, startPoint);
01101 }
01102 else
01103 {
01104 VectorCopy(es->origin, startPoint);
01105 }
01106
01107 if ( (es->eFlags&EF_JETPACK_ACTIVE) )
01108 {
01109
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
01119 if ( g_vehWeaponInfo[es->otherEntityNum2].iG2MarkShaderHandle )
01120 {
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
01164
01165
01166
01167
01168
01169
01170
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 {
01185 return;
01186 }
01187
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
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 {
01222 if ( pVeh->m_iMuzzleTag[curMuz] != -1
01223 && (broadcaster->trickedentindex&(1<<curMuz)) )
01224 {
01225 muzFX = 0;
01226 if ( pVeh->m_pVehicleInfo->weapMuzzle[curMuz] == 0 )
01227 {
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 {
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
01248
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",
01258 "VC_ATT_PRIMARY",
01259 "VC_ATT_SECONDARY",
01260 "VC_DEF_GUNS",
01261 "VC_DEF_POSITION",
01262 "VC_DEF_PRIMARY",
01263 "VC_DEF_SECONDARY",
01264 "VC_REPLY_COMING",
01265 "VC_REPLY_GO",
01266 "VC_REPLY_NO",
01267 "VC_REPLY_STAY",
01268 "VC_REPLY_YES",
01269 "VC_REQ_ASSIST",
01270 "VC_REQ_DEMO",
01271 "VC_REQ_HVY",
01272 "VC_REQ_MEDIC",
01273 "VC_REQ_SUPPLY",
01274 "VC_REQ_TECH",
01275 "VC_SPOT_AIR",
01276 "VC_SPOT_DEF",
01277 "VC_SPOT_EMPLACED",
01278 "VC_SPOT_SNIPER",
01279 "VC_SPOT_TROOP",
01280 "VC_TAC_COVER",
01281 "VC_TAC_FALLBACK",
01282 "VC_TAC_FOLLOW",
01283 "VC_TAC_HOLD",
01284 "VC_TAC_SPLIT",
01285 "VC_TAC_TOGETHER",
01286 NULL
01287 };
01288
01289
01290 const