Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

cg_event.c (32216B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 //
     23 // cg_event.c -- handle entity events at snapshot or playerstate transitions
     24 
     25 #include "cg_local.h"
     26 
     27 // for the voice chats
     28 #ifdef MISSIONPACK // bk001205
     29 #include "../../ui/menudef.h"
     30 #endif
     31 //==========================================================================
     32 
     33 /*
     34 ===================
     35 CG_PlaceString
     36 
     37 Also called by scoreboard drawing
     38 ===================
     39 */
     40 const char	*CG_PlaceString( int rank ) {
     41 	static char	str[64];
     42 	char	*s, *t;
     43 
     44 	if ( rank & RANK_TIED_FLAG ) {
     45 		rank &= ~RANK_TIED_FLAG;
     46 		t = "Tied for ";
     47 	} else {
     48 		t = "";
     49 	}
     50 
     51 	if ( rank == 1 ) {
     52 		s = S_COLOR_BLUE "1st" S_COLOR_WHITE;		// draw in blue
     53 	} else if ( rank == 2 ) {
     54 		s = S_COLOR_RED "2nd" S_COLOR_WHITE;		// draw in red
     55 	} else if ( rank == 3 ) {
     56 		s = S_COLOR_YELLOW "3rd" S_COLOR_WHITE;		// draw in yellow
     57 	} else if ( rank == 11 ) {
     58 		s = "11th";
     59 	} else if ( rank == 12 ) {
     60 		s = "12th";
     61 	} else if ( rank == 13 ) {
     62 		s = "13th";
     63 	} else if ( rank % 10 == 1 ) {
     64 		s = va("%ist", rank);
     65 	} else if ( rank % 10 == 2 ) {
     66 		s = va("%ind", rank);
     67 	} else if ( rank % 10 == 3 ) {
     68 		s = va("%ird", rank);
     69 	} else {
     70 		s = va("%ith", rank);
     71 	}
     72 
     73 	Com_sprintf( str, sizeof( str ), "%s%s", t, s );
     74 	return str;
     75 }
     76 
     77 /*
     78 =============
     79 CG_Obituary
     80 =============
     81 */
     82 static void CG_Obituary( entityState_t *ent ) {
     83 	int			mod;
     84 	int			target, attacker;
     85 	char		*message;
     86 	char		*message2;
     87 	const char	*targetInfo;
     88 	const char	*attackerInfo;
     89 	char		targetName[32];
     90 	char		attackerName[32];
     91 	gender_t	gender;
     92 	clientInfo_t	*ci;
     93 
     94 	target = ent->otherEntityNum;
     95 	attacker = ent->otherEntityNum2;
     96 	mod = ent->eventParm;
     97 
     98 	if ( target < 0 || target >= MAX_CLIENTS ) {
     99 		CG_Error( "CG_Obituary: target out of range" );
    100 	}
    101 	ci = &cgs.clientinfo[target];
    102 
    103 	if ( attacker < 0 || attacker >= MAX_CLIENTS ) {
    104 		attacker = ENTITYNUM_WORLD;
    105 		attackerInfo = NULL;
    106 	} else {
    107 		attackerInfo = CG_ConfigString( CS_PLAYERS + attacker );
    108 	}
    109 
    110 	targetInfo = CG_ConfigString( CS_PLAYERS + target );
    111 	if ( !targetInfo ) {
    112 		return;
    113 	}
    114 	Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof(targetName) - 2);
    115 	strcat( targetName, S_COLOR_WHITE );
    116 
    117 	message2 = "";
    118 
    119 	// check for single client messages
    120 
    121 	switch( mod ) {
    122 	case MOD_SUICIDE:
    123 		message = "suicides";
    124 		break;
    125 	case MOD_FALLING:
    126 		message = "cratered";
    127 		break;
    128 	case MOD_CRUSH:
    129 		message = "was squished";
    130 		break;
    131 	case MOD_WATER:
    132 		message = "sank like a rock";
    133 		break;
    134 	case MOD_SLIME:
    135 		message = "melted";
    136 		break;
    137 	case MOD_LAVA:
    138 		message = "does a back flip into the lava";
    139 		break;
    140 	case MOD_TARGET_LASER:
    141 		message = "saw the light";
    142 		break;
    143 	case MOD_TRIGGER_HURT:
    144 		message = "was in the wrong place";
    145 		break;
    146 	default:
    147 		message = NULL;
    148 		break;
    149 	}
    150 
    151 	if (attacker == target) {
    152 		gender = ci->gender;
    153 		switch (mod) {
    154 #ifdef MISSIONPACK
    155 		case MOD_KAMIKAZE:
    156 			message = "goes out with a bang";
    157 			break;
    158 #endif
    159 		case MOD_GRENADE_SPLASH:
    160 			if ( gender == GENDER_FEMALE )
    161 				message = "tripped on her own grenade";
    162 			else if ( gender == GENDER_NEUTER )
    163 				message = "tripped on its own grenade";
    164 			else
    165 				message = "tripped on his own grenade";
    166 			break;
    167 		case MOD_ROCKET_SPLASH:
    168 			if ( gender == GENDER_FEMALE )
    169 				message = "blew herself up";
    170 			else if ( gender == GENDER_NEUTER )
    171 				message = "blew itself up";
    172 			else
    173 				message = "blew himself up";
    174 			break;
    175 		case MOD_PLASMA_SPLASH:
    176 			if ( gender == GENDER_FEMALE )
    177 				message = "melted herself";
    178 			else if ( gender == GENDER_NEUTER )
    179 				message = "melted itself";
    180 			else
    181 				message = "melted himself";
    182 			break;
    183 		case MOD_BFG_SPLASH:
    184 			message = "should have used a smaller gun";
    185 			break;
    186 #ifdef MISSIONPACK
    187 		case MOD_PROXIMITY_MINE:
    188 			if( gender == GENDER_FEMALE ) {
    189 				message = "found her prox mine";
    190 			} else if ( gender == GENDER_NEUTER ) {
    191 				message = "found it's prox mine";
    192 			} else {
    193 				message = "found his prox mine";
    194 			}
    195 			break;
    196 #endif
    197 		default:
    198 			if ( gender == GENDER_FEMALE )
    199 				message = "killed herself";
    200 			else if ( gender == GENDER_NEUTER )
    201 				message = "killed itself";
    202 			else
    203 				message = "killed himself";
    204 			break;
    205 		}
    206 	}
    207 
    208 	if (message) {
    209 		CG_Printf( "%s %s.\n", targetName, message);
    210 		return;
    211 	}
    212 
    213 	// check for kill messages from the current clientNum
    214 	if ( attacker == cg.snap->ps.clientNum ) {
    215 		char	*s;
    216 
    217 		if ( cgs.gametype < GT_TEAM ) {
    218 			s = va("You fragged %s\n%s place with %i", targetName, 
    219 				CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),
    220 				cg.snap->ps.persistant[PERS_SCORE] );
    221 		} else {
    222 			s = va("You fragged %s", targetName );
    223 		}
    224 #ifdef MISSIONPACK
    225 		if (!(cg_singlePlayerActive.integer && cg_cameraOrbit.integer)) {
    226 			CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
    227 		} 
    228 #else
    229 		CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
    230 #endif
    231 
    232 		// print the text message as well
    233 	}
    234 
    235 	// check for double client messages
    236 	if ( !attackerInfo ) {
    237 		attacker = ENTITYNUM_WORLD;
    238 		strcpy( attackerName, "noname" );
    239 	} else {
    240 		Q_strncpyz( attackerName, Info_ValueForKey( attackerInfo, "n" ), sizeof(attackerName) - 2);
    241 		strcat( attackerName, S_COLOR_WHITE );
    242 		// check for kill messages about the current clientNum
    243 		if ( target == cg.snap->ps.clientNum ) {
    244 			Q_strncpyz( cg.killerName, attackerName, sizeof( cg.killerName ) );
    245 		}
    246 	}
    247 
    248 	if ( attacker != ENTITYNUM_WORLD ) {
    249 		switch (mod) {
    250 		case MOD_GRAPPLE:
    251 			message = "was caught by";
    252 			break;
    253 		case MOD_GAUNTLET:
    254 			message = "was pummeled by";
    255 			break;
    256 		case MOD_MACHINEGUN:
    257 			message = "was machinegunned by";
    258 			break;
    259 		case MOD_SHOTGUN:
    260 			message = "was gunned down by";
    261 			break;
    262 		case MOD_GRENADE:
    263 			message = "ate";
    264 			message2 = "'s grenade";
    265 			break;
    266 		case MOD_GRENADE_SPLASH:
    267 			message = "was shredded by";
    268 			message2 = "'s shrapnel";
    269 			break;
    270 		case MOD_ROCKET:
    271 			message = "ate";
    272 			message2 = "'s rocket";
    273 			break;
    274 		case MOD_ROCKET_SPLASH:
    275 			message = "almost dodged";
    276 			message2 = "'s rocket";
    277 			break;
    278 		case MOD_PLASMA:
    279 			message = "was melted by";
    280 			message2 = "'s plasmagun";
    281 			break;
    282 		case MOD_PLASMA_SPLASH:
    283 			message = "was melted by";
    284 			message2 = "'s plasmagun";
    285 			break;
    286 		case MOD_RAILGUN:
    287 			message = "was railed by";
    288 			break;
    289 		case MOD_LIGHTNING:
    290 			message = "was electrocuted by";
    291 			break;
    292 		case MOD_BFG:
    293 		case MOD_BFG_SPLASH:
    294 			message = "was blasted by";
    295 			message2 = "'s BFG";
    296 			break;
    297 #ifdef MISSIONPACK
    298 		case MOD_NAIL:
    299 			message = "was nailed by";
    300 			break;
    301 		case MOD_CHAINGUN:
    302 			message = "got lead poisoning from";
    303 			message2 = "'s Chaingun";
    304 			break;
    305 		case MOD_PROXIMITY_MINE:
    306 			message = "was too close to";
    307 			message2 = "'s Prox Mine";
    308 			break;
    309 		case MOD_KAMIKAZE:
    310 			message = "falls to";
    311 			message2 = "'s Kamikaze blast";
    312 			break;
    313 		case MOD_JUICED:
    314 			message = "was juiced by";
    315 			break;
    316 #endif
    317 		case MOD_TELEFRAG:
    318 			message = "tried to invade";
    319 			message2 = "'s personal space";
    320 			break;
    321 		default:
    322 			message = "was killed by";
    323 			break;
    324 		}
    325 
    326 		if (message) {
    327 			CG_Printf( "%s %s %s%s\n", 
    328 				targetName, message, attackerName, message2);
    329 			return;
    330 		}
    331 	}
    332 
    333 	// we don't know what it was
    334 	CG_Printf( "%s died.\n", targetName );
    335 }
    336 
    337 //==========================================================================
    338 
    339 /*
    340 ===============
    341 CG_UseItem
    342 ===============
    343 */
    344 static void CG_UseItem( centity_t *cent ) {
    345 	clientInfo_t *ci;
    346 	int			itemNum, clientNum;
    347 	gitem_t		*item;
    348 	entityState_t *es;
    349 
    350 	es = &cent->currentState;
    351 	
    352 	itemNum = (es->event & ~EV_EVENT_BITS) - EV_USE_ITEM0;
    353 	if ( itemNum < 0 || itemNum > HI_NUM_HOLDABLE ) {
    354 		itemNum = 0;
    355 	}
    356 
    357 	// print a message if the local player
    358 	if ( es->number == cg.snap->ps.clientNum ) {
    359 		if ( !itemNum ) {
    360 			CG_CenterPrint( "No item to use", SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
    361 		} else {
    362 			item = BG_FindItemForHoldable( itemNum );
    363 			CG_CenterPrint( va("Use %s", item->pickup_name), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
    364 		}
    365 	}
    366 
    367 	switch ( itemNum ) {
    368 	default:
    369 	case HI_NONE:
    370 		trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useNothingSound );
    371 		break;
    372 
    373 	case HI_TELEPORTER:
    374 		break;
    375 
    376 	case HI_MEDKIT:
    377 		clientNum = cent->currentState.clientNum;
    378 		if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
    379 			ci = &cgs.clientinfo[ clientNum ];
    380 			ci->medkitUsageTime = cg.time;
    381 		}
    382 		trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.medkitSound );
    383 		break;
    384 
    385 #ifdef MISSIONPACK
    386 	case HI_KAMIKAZE:
    387 		break;
    388 
    389 	case HI_PORTAL:
    390 		break;
    391 	case HI_INVULNERABILITY:
    392 		trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useInvulnerabilitySound );
    393 		break;
    394 #endif
    395 	}
    396 
    397 }
    398 
    399 /*
    400 ================
    401 CG_ItemPickup
    402 
    403 A new item was picked up this frame
    404 ================
    405 */
    406 static void CG_ItemPickup( int itemNum ) {
    407 	cg.itemPickup = itemNum;
    408 	cg.itemPickupTime = cg.time;
    409 	cg.itemPickupBlendTime = cg.time;
    410 	// see if it should be the grabbed weapon
    411 	if ( bg_itemlist[itemNum].giType == IT_WEAPON ) {
    412 		// select it immediately
    413 		if ( cg_autoswitch.integer && bg_itemlist[itemNum].giTag != WP_MACHINEGUN ) {
    414 			cg.weaponSelectTime = cg.time;
    415 			cg.weaponSelect = bg_itemlist[itemNum].giTag;
    416 		}
    417 	}
    418 
    419 }
    420 
    421 
    422 /*
    423 ================
    424 CG_PainEvent
    425 
    426 Also called by playerstate transition
    427 ================
    428 */
    429 void CG_PainEvent( centity_t *cent, int health ) {
    430 	char	*snd;
    431 
    432 	// don't do more than two pain sounds a second
    433 	if ( cg.time - cent->pe.painTime < 500 ) {
    434 		return;
    435 	}
    436 
    437 	if ( health < 25 ) {
    438 		snd = "*pain25_1.wav";
    439 	} else if ( health < 50 ) {
    440 		snd = "*pain50_1.wav";
    441 	} else if ( health < 75 ) {
    442 		snd = "*pain75_1.wav";
    443 	} else {
    444 		snd = "*pain100_1.wav";
    445 	}
    446 	trap_S_StartSound( NULL, cent->currentState.number, CHAN_VOICE, 
    447 		CG_CustomSound( cent->currentState.number, snd ) );
    448 
    449 	// save pain time for programitic twitch animation
    450 	cent->pe.painTime = cg.time;
    451 	cent->pe.painDirection ^= 1;
    452 }
    453 
    454 
    455 
    456 /*
    457 ==============
    458 CG_EntityEvent
    459 
    460 An entity has an event value
    461 also called by CG_CheckPlayerstateEvents
    462 ==============
    463 */
    464 #define	DEBUGNAME(x) if(cg_debugEvents.integer){CG_Printf(x"\n");}
    465 void CG_EntityEvent( centity_t *cent, vec3_t position ) {
    466 	entityState_t	*es;
    467 	int				event;
    468 	vec3_t			dir;
    469 	const char		*s;
    470 	int				clientNum;
    471 	clientInfo_t	*ci;
    472 
    473 	es = &cent->currentState;
    474 	event = es->event & ~EV_EVENT_BITS;
    475 
    476 	if ( cg_debugEvents.integer ) {
    477 		CG_Printf( "ent:%3i  event:%3i ", es->number, event );
    478 	}
    479 
    480 	if ( !event ) {
    481 		DEBUGNAME("ZEROEVENT");
    482 		return;
    483 	}
    484 
    485 	clientNum = es->clientNum;
    486 	if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
    487 		clientNum = 0;
    488 	}
    489 	ci = &cgs.clientinfo[ clientNum ];
    490 
    491 	switch ( event ) {
    492 	//
    493 	// movement generated events
    494 	//
    495 	case EV_FOOTSTEP:
    496 		DEBUGNAME("EV_FOOTSTEP");
    497 		if (cg_footsteps.integer) {
    498 			trap_S_StartSound (NULL, es->number, CHAN_BODY, 
    499 				cgs.media.footsteps[ ci->footsteps ][rand()&3] );
    500 		}
    501 		break;
    502 	case EV_FOOTSTEP_METAL:
    503 		DEBUGNAME("EV_FOOTSTEP_METAL");
    504 		if (cg_footsteps.integer) {
    505 			trap_S_StartSound (NULL, es->number, CHAN_BODY, 
    506 				cgs.media.footsteps[ FOOTSTEP_METAL ][rand()&3] );
    507 		}
    508 		break;
    509 	case EV_FOOTSPLASH:
    510 		DEBUGNAME("EV_FOOTSPLASH");
    511 		if (cg_footsteps.integer) {
    512 			trap_S_StartSound (NULL, es->number, CHAN_BODY, 
    513 				cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
    514 		}
    515 		break;
    516 	case EV_FOOTWADE:
    517 		DEBUGNAME("EV_FOOTWADE");
    518 		if (cg_footsteps.integer) {
    519 			trap_S_StartSound (NULL, es->number, CHAN_BODY, 
    520 				cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
    521 		}
    522 		break;
    523 	case EV_SWIM:
    524 		DEBUGNAME("EV_SWIM");
    525 		if (cg_footsteps.integer) {
    526 			trap_S_StartSound (NULL, es->number, CHAN_BODY, 
    527 				cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] );
    528 		}
    529 		break;
    530 
    531 
    532 	case EV_FALL_SHORT:
    533 		DEBUGNAME("EV_FALL_SHORT");
    534 		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound );
    535 		if ( clientNum == cg.predictedPlayerState.clientNum ) {
    536 			// smooth landing z changes
    537 			cg.landChange = -8;
    538 			cg.landTime = cg.time;
    539 		}
    540 		break;
    541 	case EV_FALL_MEDIUM:
    542 		DEBUGNAME("EV_FALL_MEDIUM");
    543 		// use normal pain sound
    544 		trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100_1.wav" ) );
    545 		if ( clientNum == cg.predictedPlayerState.clientNum ) {
    546 			// smooth landing z changes
    547 			cg.landChange = -16;
    548 			cg.landTime = cg.time;
    549 		}
    550 		break;
    551 	case EV_FALL_FAR:
    552 		DEBUGNAME("EV_FALL_FAR");
    553 		trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) );
    554 		cent->pe.painTime = cg.time;	// don't play a pain sound right after this
    555 		if ( clientNum == cg.predictedPlayerState.clientNum ) {
    556 			// smooth landing z changes
    557 			cg.landChange = -24;
    558 			cg.landTime = cg.time;
    559 		}
    560 		break;
    561 
    562 	case EV_STEP_4:
    563 	case EV_STEP_8:
    564 	case EV_STEP_12:
    565 	case EV_STEP_16:		// smooth out step up transitions
    566 		DEBUGNAME("EV_STEP");
    567 	{
    568 		float	oldStep;
    569 		int		delta;
    570 		int		step;
    571 
    572 		if ( clientNum != cg.predictedPlayerState.clientNum ) {
    573 			break;
    574 		}
    575 		// if we are interpolating, we don't need to smooth steps
    576 		if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ||
    577 			cg_nopredict.integer || cg_synchronousClients.integer ) {
    578 			break;
    579 		}
    580 		// check for stepping up before a previous step is completed
    581 		delta = cg.time - cg.stepTime;
    582 		if (delta < STEP_TIME) {
    583 			oldStep = cg.stepChange * (STEP_TIME - delta) / STEP_TIME;
    584 		} else {
    585 			oldStep = 0;
    586 		}
    587 
    588 		// add this amount
    589 		step = 4 * (event - EV_STEP_4 + 1 );
    590 		cg.stepChange = oldStep + step;
    591 		if ( cg.stepChange > MAX_STEP_CHANGE ) {
    592 			cg.stepChange = MAX_STEP_CHANGE;
    593 		}
    594 		cg.stepTime = cg.time;
    595 		break;
    596 	}
    597 
    598 	case EV_JUMP_PAD:
    599 		DEBUGNAME("EV_JUMP_PAD");
    600 //		CG_Printf( "EV_JUMP_PAD w/effect #%i\n", es->eventParm );
    601 		{
    602 			localEntity_t	*smoke;
    603 			vec3_t			up = {0, 0, 1};
    604 
    605 
    606 			smoke = CG_SmokePuff( cent->lerpOrigin, up, 
    607 						  32, 
    608 						  1, 1, 1, 0.33f,
    609 						  1000, 
    610 						  cg.time, 0,
    611 						  LEF_PUFF_DONT_SCALE, 
    612 						  cgs.media.smokePuffShader );
    613 		}
    614 
    615 		// boing sound at origin, jump sound on player
    616 		trap_S_StartSound ( cent->lerpOrigin, -1, CHAN_VOICE, cgs.media.jumpPadSound );
    617 		trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );
    618 		break;
    619 
    620 	case EV_JUMP:
    621 		DEBUGNAME("EV_JUMP");
    622 		trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );
    623 		break;
    624 	case EV_TAUNT:
    625 		DEBUGNAME("EV_TAUNT");
    626 		trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.wav" ) );
    627 		break;
    628 #ifdef MISSIONPACK
    629 	case EV_TAUNT_YES:
    630 		DEBUGNAME("EV_TAUNT_YES");
    631 		CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_YES);
    632 		break;
    633 	case EV_TAUNT_NO:
    634 		DEBUGNAME("EV_TAUNT_NO");
    635 		CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_NO);
    636 		break;
    637 	case EV_TAUNT_FOLLOWME:
    638 		DEBUGNAME("EV_TAUNT_FOLLOWME");
    639 		CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_FOLLOWME);
    640 		break;
    641 	case EV_TAUNT_GETFLAG:
    642 		DEBUGNAME("EV_TAUNT_GETFLAG");
    643 		CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONGETFLAG);
    644 		break;
    645 	case EV_TAUNT_GUARDBASE:
    646 		DEBUGNAME("EV_TAUNT_GUARDBASE");
    647 		CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONDEFENSE);
    648 		break;
    649 	case EV_TAUNT_PATROL:
    650 		DEBUGNAME("EV_TAUNT_PATROL");
    651 		CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONPATROL);
    652 		break;
    653 #endif
    654 	case EV_WATER_TOUCH:
    655 		DEBUGNAME("EV_WATER_TOUCH");
    656 		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrInSound );
    657 		break;
    658 	case EV_WATER_LEAVE:
    659 		DEBUGNAME("EV_WATER_LEAVE");
    660 		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound );
    661 		break;
    662 	case EV_WATER_UNDER:
    663 		DEBUGNAME("EV_WATER_UNDER");
    664 		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound );
    665 		break;
    666 	case EV_WATER_CLEAR:
    667 		DEBUGNAME("EV_WATER_CLEAR");
    668 		trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.wav" ) );
    669 		break;
    670 
    671 	case EV_ITEM_PICKUP:
    672 		DEBUGNAME("EV_ITEM_PICKUP");
    673 		{
    674 			gitem_t	*item;
    675 			int		index;
    676 
    677 			index = es->eventParm;		// player predicted
    678 
    679 			if ( index < 1 || index >= bg_numItems ) {
    680 				break;
    681 			}
    682 			item = &bg_itemlist[ index ];
    683 
    684 			// powerups and team items will have a separate global sound, this one
    685 			// will be played at prediction time
    686 			if ( item->giType == IT_POWERUP || item->giType == IT_TEAM) {
    687 				trap_S_StartSound (NULL, es->number, CHAN_AUTO,	cgs.media.n_healthSound );
    688 			} else if (item->giType == IT_PERSISTANT_POWERUP) {
    689 #ifdef MISSIONPACK
    690 				switch (item->giTag ) {
    691 					case PW_SCOUT:
    692 						trap_S_StartSound (NULL, es->number, CHAN_AUTO,	cgs.media.scoutSound );
    693 					break;
    694 					case PW_GUARD:
    695 						trap_S_StartSound (NULL, es->number, CHAN_AUTO,	cgs.media.guardSound );
    696 					break;
    697 					case PW_DOUBLER:
    698 						trap_S_StartSound (NULL, es->number, CHAN_AUTO,	cgs.media.doublerSound );
    699 					break;
    700 					case PW_AMMOREGEN:
    701 						trap_S_StartSound (NULL, es->number, CHAN_AUTO,	cgs.media.ammoregenSound );
    702 					break;
    703 				}
    704 #endif
    705 			} else {
    706 				trap_S_StartSound (NULL, es->number, CHAN_AUTO,	trap_S_RegisterSound( item->pickup_sound, qfalse ) );
    707 			}
    708 
    709 			// show icon and name on status bar
    710 			if ( es->number == cg.snap->ps.clientNum ) {
    711 				CG_ItemPickup( index );
    712 			}
    713 		}
    714 		break;
    715 
    716 	case EV_GLOBAL_ITEM_PICKUP:
    717 		DEBUGNAME("EV_GLOBAL_ITEM_PICKUP");
    718 		{
    719 			gitem_t	*item;
    720 			int		index;
    721 
    722 			index = es->eventParm;		// player predicted
    723 
    724 			if ( index < 1 || index >= bg_numItems ) {
    725 				break;
    726 			}
    727 			item = &bg_itemlist[ index ];
    728 			// powerup pickups are global
    729 			if( item->pickup_sound ) {
    730 				trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) );
    731 			}
    732 
    733 			// show icon and name on status bar
    734 			if ( es->number == cg.snap->ps.clientNum ) {
    735 				CG_ItemPickup( index );
    736 			}
    737 		}
    738 		break;
    739 
    740 	//
    741 	// weapon events
    742 	//
    743 	case EV_NOAMMO:
    744 		DEBUGNAME("EV_NOAMMO");
    745 //		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.noAmmoSound );
    746 		if ( es->number == cg.snap->ps.clientNum ) {
    747 			CG_OutOfAmmoChange();
    748 		}
    749 		break;
    750 	case EV_CHANGE_WEAPON:
    751 		DEBUGNAME("EV_CHANGE_WEAPON");
    752 		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound );
    753 		break;
    754 	case EV_FIRE_WEAPON:
    755 		DEBUGNAME("EV_FIRE_WEAPON");
    756 		CG_FireWeapon( cent );
    757 		break;
    758 
    759 	case EV_USE_ITEM0:
    760 		DEBUGNAME("EV_USE_ITEM0");
    761 		CG_UseItem( cent );
    762 		break;
    763 	case EV_USE_ITEM1:
    764 		DEBUGNAME("EV_USE_ITEM1");
    765 		CG_UseItem( cent );
    766 		break;
    767 	case EV_USE_ITEM2:
    768 		DEBUGNAME("EV_USE_ITEM2");
    769 		CG_UseItem( cent );
    770 		break;
    771 	case EV_USE_ITEM3:
    772 		DEBUGNAME("EV_USE_ITEM3");
    773 		CG_UseItem( cent );
    774 		break;
    775 	case EV_USE_ITEM4:
    776 		DEBUGNAME("EV_USE_ITEM4");
    777 		CG_UseItem( cent );
    778 		break;
    779 	case EV_USE_ITEM5:
    780 		DEBUGNAME("EV_USE_ITEM5");
    781 		CG_UseItem( cent );
    782 		break;
    783 	case EV_USE_ITEM6:
    784 		DEBUGNAME("EV_USE_ITEM6");
    785 		CG_UseItem( cent );
    786 		break;
    787 	case EV_USE_ITEM7:
    788 		DEBUGNAME("EV_USE_ITEM7");
    789 		CG_UseItem( cent );
    790 		break;
    791 	case EV_USE_ITEM8:
    792 		DEBUGNAME("EV_USE_ITEM8");
    793 		CG_UseItem( cent );
    794 		break;
    795 	case EV_USE_ITEM9:
    796 		DEBUGNAME("EV_USE_ITEM9");
    797 		CG_UseItem( cent );
    798 		break;
    799 	case EV_USE_ITEM10:
    800 		DEBUGNAME("EV_USE_ITEM10");
    801 		CG_UseItem( cent );
    802 		break;
    803 	case EV_USE_ITEM11:
    804 		DEBUGNAME("EV_USE_ITEM11");
    805 		CG_UseItem( cent );
    806 		break;
    807 	case EV_USE_ITEM12:
    808 		DEBUGNAME("EV_USE_ITEM12");
    809 		CG_UseItem( cent );
    810 		break;
    811 	case EV_USE_ITEM13:
    812 		DEBUGNAME("EV_USE_ITEM13");
    813 		CG_UseItem( cent );
    814 		break;
    815 	case EV_USE_ITEM14:
    816 		DEBUGNAME("EV_USE_ITEM14");
    817 		CG_UseItem( cent );
    818 		break;
    819 
    820 	//=================================================================
    821 
    822 	//
    823 	// other events
    824 	//
    825 	case EV_PLAYER_TELEPORT_IN:
    826 		DEBUGNAME("EV_PLAYER_TELEPORT_IN");
    827 		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleInSound );
    828 		CG_SpawnEffect( position);
    829 		break;
    830 
    831 	case EV_PLAYER_TELEPORT_OUT:
    832 		DEBUGNAME("EV_PLAYER_TELEPORT_OUT");
    833 		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleOutSound );
    834 		CG_SpawnEffect(  position);
    835 		break;
    836 
    837 	case EV_ITEM_POP:
    838 		DEBUGNAME("EV_ITEM_POP");
    839 		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );
    840 		break;
    841 	case EV_ITEM_RESPAWN:
    842 		DEBUGNAME("EV_ITEM_RESPAWN");
    843 		cent->miscTime = cg.time;	// scale up from this
    844 		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );
    845 		break;
    846 
    847 	case EV_GRENADE_BOUNCE:
    848 		DEBUGNAME("EV_GRENADE_BOUNCE");
    849 		if ( rand() & 1 ) {
    850 			trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb1aSound );
    851 		} else {
    852 			trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb2aSound );
    853 		}
    854 		break;
    855 
    856 #ifdef MISSIONPACK
    857 	case EV_PROXIMITY_MINE_STICK:
    858 		DEBUGNAME("EV_PROXIMITY_MINE_STICK");
    859 		if( es->eventParm & SURF_FLESH ) {
    860 			trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimplSound );
    861 		} else 	if( es->eventParm & SURF_METALSTEPS ) {
    862 			trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpmSound );
    863 		} else {
    864 			trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpdSound );
    865 		}
    866 		break;
    867 
    868 	case EV_PROXIMITY_MINE_TRIGGER:
    869 		DEBUGNAME("EV_PROXIMITY_MINE_TRIGGER");
    870 		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbactvSound );
    871 		break;
    872 	case EV_KAMIKAZE:
    873 		DEBUGNAME("EV_KAMIKAZE");
    874 		CG_KamikazeEffect( cent->lerpOrigin );
    875 		break;
    876 	case EV_OBELISKEXPLODE:
    877 		DEBUGNAME("EV_OBELISKEXPLODE");
    878 		CG_ObeliskExplode( cent->lerpOrigin, es->eventParm );
    879 		break;
    880 	case EV_OBELISKPAIN:
    881 		DEBUGNAME("EV_OBELISKPAIN");
    882 		CG_ObeliskPain( cent->lerpOrigin );
    883 		break;
    884 	case EV_INVUL_IMPACT:
    885 		DEBUGNAME("EV_INVUL_IMPACT");
    886 		CG_InvulnerabilityImpact( cent->lerpOrigin, cent->currentState.angles );
    887 		break;
    888 	case EV_JUICED:
    889 		DEBUGNAME("EV_JUICED");
    890 		CG_InvulnerabilityJuiced( cent->lerpOrigin );
    891 		break;
    892 	case EV_LIGHTNINGBOLT:
    893 		DEBUGNAME("EV_LIGHTNINGBOLT");
    894 		CG_LightningBoltBeam(es->origin2, es->pos.trBase);
    895 		break;
    896 #endif
    897 	case EV_SCOREPLUM:
    898 		DEBUGNAME("EV_SCOREPLUM");
    899 		CG_ScorePlum( cent->currentState.otherEntityNum, cent->lerpOrigin, cent->currentState.time );
    900 		break;
    901 
    902 	//
    903 	// missile impacts
    904 	//
    905 	case EV_MISSILE_HIT:
    906 		DEBUGNAME("EV_MISSILE_HIT");
    907 		ByteToDir( es->eventParm, dir );
    908 		CG_MissileHitPlayer( es->weapon, position, dir, es->otherEntityNum );
    909 		break;
    910 
    911 	case EV_MISSILE_MISS:
    912 		DEBUGNAME("EV_MISSILE_MISS");
    913 		ByteToDir( es->eventParm, dir );
    914 		CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_DEFAULT );
    915 		break;
    916 
    917 	case EV_MISSILE_MISS_METAL:
    918 		DEBUGNAME("EV_MISSILE_MISS_METAL");
    919 		ByteToDir( es->eventParm, dir );
    920 		CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_METAL );
    921 		break;
    922 
    923 	case EV_RAILTRAIL:
    924 		DEBUGNAME("EV_RAILTRAIL");
    925 		cent->currentState.weapon = WP_RAILGUN;
    926 		// if the end was on a nomark surface, don't make an explosion
    927 		CG_RailTrail( ci, es->origin2, es->pos.trBase );
    928 		if ( es->eventParm != 255 ) {
    929 			ByteToDir( es->eventParm, dir );
    930 			CG_MissileHitWall( es->weapon, es->clientNum, position, dir, IMPACTSOUND_DEFAULT );
    931 		}
    932 		break;
    933 
    934 	case EV_BULLET_HIT_WALL:
    935 		DEBUGNAME("EV_BULLET_HIT_WALL");
    936 		ByteToDir( es->eventParm, dir );
    937 		CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD );
    938 		break;
    939 
    940 	case EV_BULLET_HIT_FLESH:
    941 		DEBUGNAME("EV_BULLET_HIT_FLESH");
    942 		CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm );
    943 		break;
    944 
    945 	case EV_SHOTGUN:
    946 		DEBUGNAME("EV_SHOTGUN");
    947 		CG_ShotgunFire( es );
    948 		break;
    949 
    950 	case EV_GENERAL_SOUND:
    951 		DEBUGNAME("EV_GENERAL_SOUND");
    952 		if ( cgs.gameSounds[ es->eventParm ] ) {
    953 			trap_S_StartSound (NULL, es->number, CHAN_VOICE, cgs.gameSounds[ es->eventParm ] );
    954 		} else {
    955 			s = CG_ConfigString( CS_SOUNDS + es->eventParm );
    956 			trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, s ) );
    957 		}
    958 		break;
    959 
    960 	case EV_GLOBAL_SOUND:	// play from the player's head so it never diminishes
    961 		DEBUGNAME("EV_GLOBAL_SOUND");
    962 		if ( cgs.gameSounds[ es->eventParm ] ) {
    963 			trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] );
    964 		} else {
    965 			s = CG_ConfigString( CS_SOUNDS + es->eventParm );
    966 			trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, CG_CustomSound( es->number, s ) );
    967 		}
    968 		break;
    969 
    970 	case EV_GLOBAL_TEAM_SOUND:	// play from the player's head so it never diminishes
    971 		{
    972 			DEBUGNAME("EV_GLOBAL_TEAM_SOUND");
    973 			switch( es->eventParm ) {
    974 				case GTS_RED_CAPTURE: // CTF: red team captured the blue flag, 1FCTF: red team captured the neutral flag
    975 					if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED )
    976 						CG_AddBufferedSound( cgs.media.captureYourTeamSound );
    977 					else
    978 						CG_AddBufferedSound( cgs.media.captureOpponentSound );
    979 					break;
    980 				case GTS_BLUE_CAPTURE: // CTF: blue team captured the red flag, 1FCTF: blue team captured the neutral flag
    981 					if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE )
    982 						CG_AddBufferedSound( cgs.media.captureYourTeamSound );
    983 					else
    984 						CG_AddBufferedSound( cgs.media.captureOpponentSound );
    985 					break;
    986 				case GTS_RED_RETURN: // CTF: blue flag returned, 1FCTF: never used
    987 					if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED )
    988 						CG_AddBufferedSound( cgs.media.returnYourTeamSound );
    989 					else
    990 						CG_AddBufferedSound( cgs.media.returnOpponentSound );
    991 					//
    992 					CG_AddBufferedSound( cgs.media.blueFlagReturnedSound );
    993 					break;
    994 				case GTS_BLUE_RETURN: // CTF red flag returned, 1FCTF: neutral flag returned
    995 					if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE )
    996 						CG_AddBufferedSound( cgs.media.returnYourTeamSound );
    997 					else
    998 						CG_AddBufferedSound( cgs.media.returnOpponentSound );
    999 					//
   1000 					CG_AddBufferedSound( cgs.media.redFlagReturnedSound );
   1001 					break;
   1002 
   1003 				case GTS_RED_TAKEN: // CTF: red team took blue flag, 1FCTF: blue team took the neutral flag
   1004 					// if this player picked up the flag then a sound is played in CG_CheckLocalSounds
   1005 					if (cg.snap->ps.powerups[PW_BLUEFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {
   1006 					}
   1007 					else {
   1008 					if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
   1009 #ifdef MISSIONPACK
   1010 							if (cgs.gametype == GT_1FCTF) 
   1011 								CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound );
   1012 							else
   1013 #endif
   1014 						 	CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound );
   1015 						}
   1016 						else if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
   1017 #ifdef MISSIONPACK
   1018 							if (cgs.gametype == GT_1FCTF)
   1019 								CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound );
   1020 							else
   1021 #endif
   1022  							CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound );
   1023 						}
   1024 					}
   1025 					break;
   1026 				case GTS_BLUE_TAKEN: // CTF: blue team took the red flag, 1FCTF red team took the neutral flag
   1027 					// if this player picked up the flag then a sound is played in CG_CheckLocalSounds
   1028 					if (cg.snap->ps.powerups[PW_REDFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) {
   1029 					}
   1030 					else {
   1031 						if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
   1032 #ifdef MISSIONPACK
   1033 							if (cgs.gametype == GT_1FCTF)
   1034 								CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound );
   1035 							else
   1036 #endif
   1037 							CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound );
   1038 						}
   1039 						else if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
   1040 #ifdef MISSIONPACK
   1041 							if (cgs.gametype == GT_1FCTF)
   1042 								CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound );
   1043 							else
   1044 #endif
   1045 							CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound );
   1046 						}
   1047 					}
   1048 					break;
   1049 				case GTS_REDOBELISK_ATTACKED: // Overload: red obelisk is being attacked
   1050 					if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
   1051 						CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound );
   1052 					}
   1053 					break;
   1054 				case GTS_BLUEOBELISK_ATTACKED: // Overload: blue obelisk is being attacked
   1055 					if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
   1056 						CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound );
   1057 					}
   1058 					break;
   1059 
   1060 				case GTS_REDTEAM_SCORED:
   1061 					CG_AddBufferedSound(cgs.media.redScoredSound);
   1062 					break;
   1063 				case GTS_BLUETEAM_SCORED:
   1064 					CG_AddBufferedSound(cgs.media.blueScoredSound);
   1065 					break;
   1066 				case GTS_REDTEAM_TOOK_LEAD:
   1067 					CG_AddBufferedSound(cgs.media.redLeadsSound);
   1068 					break;
   1069 				case GTS_BLUETEAM_TOOK_LEAD:
   1070 					CG_AddBufferedSound(cgs.media.blueLeadsSound);
   1071 					break;
   1072 				case GTS_TEAMS_ARE_TIED:
   1073 					CG_AddBufferedSound( cgs.media.teamsTiedSound );
   1074 					break;
   1075 #ifdef MISSIONPACK
   1076 				case GTS_KAMIKAZE:
   1077 					trap_S_StartLocalSound(cgs.media.kamikazeFarSound, CHAN_ANNOUNCER);
   1078 					break;
   1079 #endif
   1080 				default:
   1081 					break;
   1082 			}
   1083 			break;
   1084 		}
   1085 
   1086 	case EV_PAIN:
   1087 		// local player sounds are triggered in CG_CheckLocalSounds,
   1088 		// so ignore events on the player
   1089 		DEBUGNAME("EV_PAIN");
   1090 		if ( cent->currentState.number != cg.snap->ps.clientNum ) {
   1091 			CG_PainEvent( cent, es->eventParm );
   1092 		}
   1093 		break;
   1094 
   1095 	case EV_DEATH1:
   1096 	case EV_DEATH2:
   1097 	case EV_DEATH3:
   1098 		DEBUGNAME("EV_DEATHx");
   1099 		trap_S_StartSound( NULL, es->number, CHAN_VOICE, 
   1100 				CG_CustomSound( es->number, va("*death%i.wav", event - EV_DEATH1 + 1) ) );
   1101 		break;
   1102 
   1103 
   1104 	case EV_OBITUARY:
   1105 		DEBUGNAME("EV_OBITUARY");
   1106 		CG_Obituary( es );
   1107 		break;
   1108 
   1109 	//
   1110 	// powerup events
   1111 	//
   1112 	case EV_POWERUP_QUAD:
   1113 		DEBUGNAME("EV_POWERUP_QUAD");
   1114 		if ( es->number == cg.snap->ps.clientNum ) {
   1115 			cg.powerupActive = PW_QUAD;
   1116 			cg.powerupTime = cg.time;
   1117 		}
   1118 		trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.quadSound );
   1119 		break;
   1120 	case EV_POWERUP_BATTLESUIT:
   1121 		DEBUGNAME("EV_POWERUP_BATTLESUIT");
   1122 		if ( es->number == cg.snap->ps.clientNum ) {
   1123 			cg.powerupActive = PW_BATTLESUIT;
   1124 			cg.powerupTime = cg.time;
   1125 		}
   1126 		trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.protectSound );
   1127 		break;
   1128 	case EV_POWERUP_REGEN:
   1129 		DEBUGNAME("EV_POWERUP_REGEN");
   1130 		if ( es->number == cg.snap->ps.clientNum ) {
   1131 			cg.powerupActive = PW_REGEN;
   1132 			cg.powerupTime = cg.time;
   1133 		}
   1134 		trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.regenSound );
   1135 		break;
   1136 
   1137 	case EV_GIB_PLAYER:
   1138 		DEBUGNAME("EV_GIB_PLAYER");
   1139 		// don't play gib sound when using the kamikaze because it interferes
   1140 		// with the kamikaze sound, downside is that the gib sound will also
   1141 		// not be played when someone is gibbed while just carrying the kamikaze
   1142 		if ( !(es->eFlags & EF_KAMIKAZE) ) {
   1143 			trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.gibSound );
   1144 		}
   1145 		CG_GibPlayer( cent->lerpOrigin );
   1146 		break;
   1147 
   1148 	case EV_STOPLOOPINGSOUND:
   1149 		DEBUGNAME("EV_STOPLOOPINGSOUND");
   1150 		trap_S_StopLoopingSound( es->number );
   1151 		es->loopSound = 0;
   1152 		break;
   1153 
   1154 	case EV_DEBUG_LINE:
   1155 		DEBUGNAME("EV_DEBUG_LINE");
   1156 		CG_Beam( cent );
   1157 		break;
   1158 
   1159 	default:
   1160 		DEBUGNAME("UNKNOWN");
   1161 		CG_Error( "Unknown event: %i", event );
   1162 		break;
   1163 	}
   1164 
   1165 }
   1166 
   1167 
   1168 /*
   1169 ==============
   1170 CG_CheckEvents
   1171 
   1172 ==============
   1173 */
   1174 void CG_CheckEvents( centity_t *cent ) {
   1175 	// check for event-only entities
   1176 	if ( cent->currentState.eType > ET_EVENTS ) {
   1177 		if ( cent->previousEvent ) {
   1178 			return;	// already fired
   1179 		}
   1180 		// if this is a player event set the entity number of the client entity number
   1181 		if ( cent->currentState.eFlags & EF_PLAYER_EVENT ) {
   1182 			cent->currentState.number = cent->currentState.otherEntityNum;
   1183 		}
   1184 
   1185 		cent->previousEvent = 1;
   1186 
   1187 		cent->currentState.event = cent->currentState.eType - ET_EVENTS;
   1188 	} else {
   1189 		// check for events riding with another entity
   1190 		if ( cent->currentState.event == cent->previousEvent ) {
   1191 			return;
   1192 		}
   1193 		cent->previousEvent = cent->currentState.event;
   1194 		if ( ( cent->currentState.event & ~EV_EVENT_BITS ) == 0 ) {
   1195 			return;
   1196 		}
   1197 	}
   1198 
   1199 	// calculate the position at exactly the frame time
   1200 	BG_EvaluateTrajectory( &cent->currentState.pos, cg.snap->serverTime, cent->lerpOrigin );
   1201 	CG_SetEntitySoundPosition( cent );
   1202 
   1203 	CG_EntityEvent( cent, cent->lerpOrigin );
   1204 }
   1205