#include "cg_local.h"
#include "wolfcam_local.h"

extern void CG_StartShakeCamera( float param );
extern void CG_Tracer( vec3_t source, vec3_t dest, int sparks );

extern void CG_StartFootStepSound( bg_playerclass_t* classInfo, entityState_t *es, sfxHandle_t sfx);
extern void CG_ItemPickup( int itemNum );
extern void CG_MortarImpact( centity_t *cent, vec3_t origin, int sfx, qboolean dist );
extern void CG_Explode(centity_t *cent, vec3_t origin, vec3_t dir, qhandle_t shader);
extern void CG_Rubble(centity_t *cent, vec3_t origin, vec3_t dir, qhandle_t shader);
extern void CG_Effect(centity_t *cent, vec3_t origin, vec3_t dir);
extern void CG_Shard(centity_t *cent, vec3_t origin, vec3_t dir);
extern void CG_ShardJunk (centity_t *cent, vec3_t origin, vec3_t dir);
extern void CG_Debris (centity_t *cent, vec3_t origin, vec3_t dir);
extern void CG_MortarMiss( centity_t *cent, vec3_t origin );

#define POSSIBLE_PIECES 6

typedef struct fxSound_s {
    int max;
    qhandle_t sound[3];
    const char *soundfile[3];
} fxSound_t;

extern fxSound_t fxSounds[POSSIBLE_PIECES];

static void Wolfcam_Obituary( entityState_t *ent ) {
	int			mod;
	int			target, attacker;
	char		*message;
	char		*message2;
	char		targetName[32];
	char		attackerName[32];
	clientInfo_t	*ci, *ca; // JPW NERVE ca = attacker
	qhandle_t	deathShader = cgs.media.pmImages[PM_DEATH];
    int clientNum;

	target = ent->otherEntityNum;
	attacker = ent->otherEntityNum2;
	mod = ent->eventParm;

    if (wolfcam_gameVersion == WOLFCAM_ETPRO) {
        target = ent->time;
        attacker = ent->time2;
        mod = ent->eFlags;
    }
    if (wolfcam_ent > -1)
        clientNum = cgs.clientinfo[wolfcam_ent].clientNum;
    else
        clientNum = cg.snap->ps.clientNum;

	if ( target < 0 || target >= MAX_CLIENTS ) {
		CG_Error( "Wolfcam_Obituary: target out of range" );
	}
	ci = &cgs.clientinfo[target];

	if ( attacker < 0 || attacker >= MAX_CLIENTS ) {
		attacker = ENTITYNUM_WORLD;
		ca = NULL;
	} else {
		ca = &cgs.clientinfo[attacker];
	}

	Q_strncpyz( targetName, ci->name, sizeof(targetName) - 2);
	strcat( targetName, S_COLOR_WHITE );

    if (ca) {
        Q_strncpyz( attackerName, ca->name, sizeof(attackerName) - 2);
        strcat( attackerName, S_COLOR_WHITE );
    } //FIXME wolfcam else 'noname'

	message2 = "";

	// check for single client messages
	switch( mod ) {
	case MOD_SUICIDE:
		message = "committed suicide";
		break;
	case MOD_FALLING:
		message = "fell to his death";
		break;
	case MOD_CRUSH:
		message = "was crushed";
		break;
	case MOD_WATER:
		message = "drowned";
		break;
	case MOD_SLIME:
		message = "died by toxic materials";
		break;
	case MOD_TRIGGER_HURT:
	case MOD_TELEFRAG: // rain - added TELEFRAG and TARGET_LASER, just in case
	case MOD_TARGET_LASER:
		message = "was killed";
		break;
	case MOD_CRUSH_CONSTRUCTIONDEATH_NOATTACKER:
		message = "got buried under a pile of rubble";
		break;
	case MOD_LAVA: // rain
		message = "was incinerated";
		break;
	default:
		message = NULL;
		break;
	}

	if( attacker == target ) {
		switch (mod) {
		case MOD_DYNAMITE:
			message = "dynamited himself to pieces";
			break;
		case MOD_GRENADE_LAUNCHER:
		case MOD_GRENADE_PINEAPPLE: // rain - added PINEAPPLE
			message = "dove on his own grenade";
			break;
		case MOD_PANZERFAUST:
			message = "vaporized himself";
			break;
		case MOD_FLAMETHROWER: // rain
			message = "played with fire";
			break;
		case MOD_AIRSTRIKE:
			message = "obliterated himself";
			break;
		case MOD_ARTY:
			message = "fired-for-effect on himself";
			break;
		case MOD_EXPLOSIVE:
			message = "died in his own explosion";
			break;
		// rain - everything from this point on is sorted by MOD, didn't
		// resort existing messages to avoid differences between pre
		// and post-patch code (for source patching)
		case MOD_GPG40:
		case MOD_M7: // rain
			//bani - more amusing, less wordy
			message = "ate his own rifle grenade";
			break;
		case MOD_LANDMINE: // rain
			//bani - slightly more amusing
			message = "failed to spot his own landmine";
			break;
		case MOD_SATCHEL: // rain
			message = "embraced his own satchel explosion";
			break;
		case MOD_TRIPMINE: // rain - dormant code
			message = "forgot where his tripmine was";
			break;
		case MOD_CRUSH_CONSTRUCTION: // rain
			message = "engineered himself into oblivion";
			break;
		case MOD_CRUSH_CONSTRUCTIONDEATH: // rain
			message = "buried himself alive";
			break;
		case MOD_MORTAR: // rain
			message = "never saw his own mortar round coming";
			break;
		case MOD_SMOKEGRENADE: // rain
			// bani - more amusing
			message = "danced on his airstrike marker";
			break;
		// no obituary message if changing teams
		case MOD_SWITCHTEAM:
			return;
		default:
			message = "killed himself";
			break;
		}
	}

	if (message) {
		message = CG_TranslateString( message );
		CG_AddPMItem( PM_DEATH, va( "%s %s.", targetName, message ), deathShader );
		return;
	}

	// check for kill messages from the current clientNum
	if( attacker == clientNum ) {
		char	*s;

		if ( ci->team == ca->team ) {
			if (mod == MOD_SWAP_PLACES) {
				s = va("%s %s", CG_TranslateString( "You swapped places with" ), targetName );
			} else {
				s = va("%s %s", CG_TranslateString( "You killed ^1TEAMMATE^7" ), targetName );
			}
		} else {
			s = va("%s %s", CG_TranslateString( "You killed" ), targetName );
		}
		CG_PriorityCenterPrint( s, SCREEN_HEIGHT * 0.85, BIGCHAR_WIDTH * 0.6, 1 );
   
		// print the text message as well
	}
    if (target == clientNum) {
        char *s;
        if (ci->team == ca->team) {
            if (mod == MOD_SWAP_PLACES) {
                s = va ("%s %s", attackerName, CG_TranslateString("Swapped places with you"));
            } else {
                s = va ("%s %s", attackerName, CG_TranslateString("^1TEAMKILLED ^0you"));
                //CG_TranslateString("^1TEAMATE^7"), attackerName, CG_TranslateString(" ^0killed you"));
            }
        } else {
            s = va ("%s %s", attackerName, CG_TranslateString("^0killed ^0you"));
        }
        CG_PriorityCenterPrint( s, SCREEN_HEIGHT * 0.85, BIGCHAR_WIDTH * 0.6, 1);
    }
	// check for double client messages
	if ( !ca ) {
		strcpy( attackerName, "noname" );
	} else {
		Q_strncpyz( attackerName, ca->name, sizeof(attackerName) - 2);
		strcat( attackerName, S_COLOR_WHITE );

		// check for kill messages about the current clientNum
		if ( target == clientNum ) {
			Q_strncpyz( cg.killerName, attackerName, sizeof( cg.killerName ) );
		}
	}

	if( ca ) {
		switch( mod ) {
		case MOD_KNIFE:
			message = "was stabbed by";
			message2 = "'s knife";
			// OSP - goat luvin
//			if( attacker == clientNum || target == clientNum ) {
//				trap_S_StartSound( cg.snap->ps.origin, clientNum, CHAN_AUTO, cgs.media.goatAxis );
//			}
			break;

		case MOD_AKIMBO_COLT:
		case MOD_AKIMBO_SILENCEDCOLT:
			message = "was killed by";
			message2 = "'s Akimbo .45ACP 1911s";
			break;

		case MOD_AKIMBO_LUGER:
		case MOD_AKIMBO_SILENCEDLUGER:
			message = "was killed by";
			message2 = "'s Akimbo Luger 9mms";
			break;

		case MOD_SILENCER:
		case MOD_LUGER:
			message = "was killed by";
			message2 = "'s Luger 9mm";
			break;

		case MOD_SILENCED_COLT:
		case MOD_COLT:
			message = "was killed by";
			message2 = "'s .45ACP 1911";
			break;

		case MOD_MP40:
			message = "was killed by";
			message2 = "'s MP40";
			break;

		case MOD_THOMPSON:
			message = "was killed by";
			message2 = "'s Thompson";
			break;

		case MOD_STEN:
			message = "was killed by";
			message2 = "'s Sten";
			break;

		case MOD_DYNAMITE:
			message = "was blasted by";
			message2 = "'s dynamite";
			break;

		case MOD_PANZERFAUST:
			message = "was blasted by";
			message2 = "'s Panzerfaust";
			break;

		case MOD_GRENADE_LAUNCHER:
		case MOD_GRENADE_PINEAPPLE:
			message = "was exploded by";
			message2 = "'s grenade";
			break;

		case MOD_FLAMETHROWER:
			message = "was cooked by";
			message2 = "'s flamethrower";
			break;

		case MOD_MORTAR:
			message = "never saw";
			message2 = "'s mortar round coming";
			break;

		case MOD_MACHINEGUN:
			message = "was perforated by";
			message2 = "'s crew-served MG";
			break;

		case MOD_BROWNING:
			message = "was perforated by";
			message2 = "'s tank-mounted browning 30cal";
			break;

		case MOD_MG42:
			message = "was perforated by";
			message2 = "'s tank-mounted MG42";
			break;

		case MOD_AIRSTRIKE:
			message = "was blasted by";
			message2 = "'s support fire";
			break;

		case MOD_ARTY:
			message = "was shelled by";
			message2 = "'s artillery support";
			break;

		case MOD_SWAP_PLACES:
			message = "^2swapped places with^7";
			message2="";
			break;

		case MOD_KAR98:	// same weapon really
		case MOD_K43:
			message = "was killed by";
			message2 = "'s K43";
			break;

		case MOD_CARBINE: // same weapon really
		case MOD_GARAND:
			message = "was killed by";
			message2 = "'s Garand";
			break;

		case MOD_GPG40:
		case MOD_M7:
			message = "was killed by";
			message2 = "'s rifle grenade";
			break;

		case MOD_LANDMINE:
			message = "failed to spot";
			message2 = "'s Landmine";
			break;

		case MOD_CRUSH_CONSTRUCTION:
			message = "got caught in";
			message2 = "'s construction madness";
			break;

		case MOD_CRUSH_CONSTRUCTIONDEATH:
			message = "got burried under";
			message2 = "'s rubble";
			break;

		case MOD_MOBILE_MG42:
			message = "was mown down by";
			message2 = "'s Mobile MG42";
			break;

		case MOD_GARAND_SCOPE:
			message = "was silenced by";
			message2 = "'s Garand";
			break;

		case MOD_K43_SCOPE:
			message = "was silenced by";
			message2 = "'s K43";
			break;

		case MOD_FG42:
			message = "was killed by";
			message2 = "'s FG42";
			break;

		case MOD_FG42SCOPE:
			message = "was sniped by";
			message2 = "'s FG42";
			break;

		case MOD_SATCHEL:
			message = "was blasted by";
			message2 = "'s Satchel Charge";
			break;
		
		case MOD_TRIPMINE: // rain - dormant code
			message = "was detonated by";
			message2 = "'s trip mine";
			break;
		
		case MOD_SMOKEGRENADE: // rain
			message = "stood on";
			message2 = "'s airstrike marker";
			break;

		default:
			message = "was killed by";
			break;
		}

		if( ci->team == ca->team ) {
			message = "^1WAS KILLED BY TEAMMATE^7";
			message2="";
		}

		if (message) {
			message = CG_TranslateString( message );
			if ( message2 ) {
				message2 = CG_TranslateString( message2 );
				CG_AddPMItem( PM_DEATH, va( "%s %s %s%s", targetName, message, attackerName, message2 ), deathShader );
				//CG_AddPMItem( PM_DEATH, va( "%s ^7(%d) %s %s ^7(%d)%s", targetName, target, message, attackerName, attacker, message2 ), deathShader );
//				CG_Printf( "[cgnotify]%s %s %s%s\n", targetName, message, attackerName, message2 );
			}
			return;
		}
	}

	// we don't know what it was
	switch( mod ) {
		default:
			CG_AddPMItem( PM_DEATH, va( "%s died.", targetName ), deathShader );
			break;
	}
}

//static int (QDECL *syscall)( int arg, ... ) = (int (QDECL *)( int, ...))-1;
qboolean trap_wolfcam_GetSnapshot (int snapshotNumber, snapshot_t *snapshot);

void Wolfcam_ReadNextSnapshot (void)
{
    qboolean r;
    snapshot_t *dest = NULL;
    int i;
    int snapNum;
    int currWeapon;
    int newWeap = -666;
    int n;

    return;
    //    snapNum = cgs.processedSnapshotNum + 1;
    //snapNum =  cg.latestSnapshotNum + 1;
    snapNum = cgs.processedSnapshotNum + 2;

    currWeapon = cg_entities[cgs.clientinfo[wolfcam_ent].clientNum].currentState.weapon;
    CG_Printf ("^3current weapon:%d  -- %d\n", currWeapon, snapNum);
    

    //r = trap_GetSnapshot (cgs.processedSnapshotNum + 1, dest);
    //r = syscall (CG_GETSNAPSHOT, cgs.processedSnapshotNum + 1, dest);
    r = trap_wolfcam_GetSnapshot (snapNum, dest);
#if 0

    newWeap = -666;
    for (i = 0;  i < 1;  i++, snapNum++) {
        //r = trap_GetSnapshot( snapNum, dest );
        //r = syscall (CG_GETSNAPSHOT, cgs.processedSnapshotNum + 1, dest);
        r = trap_wolfcam_GetSnapshot (snapNum, dest);
        if (!r  ||  !dest) {
            CG_Printf ("^3 couldn't get snapshot\n");
            break;
        }
        for (n = 0;  n < dest->numEntities;  n++) {
            //entityState_t *es;
            if (dest->entities[n].clientNum == cgs.clientinfo[wolfcam_ent].clientNum) {
                if (dest->entities[n].weapon != currWeapon) {
                    newWeap = dest->entities[n].weapon;
                    goto ALLDONE;
                }
            }
        }
    }

    CG_Printf ("^3 didn't get weapon :(\n");
 ALLDONE:
#endif

    CG_Printf ("^3new weapon: %d\n", newWeap);
}

    
            
    
extern void CG_AddBulletParticles( vec3_t origin, vec3_t dir, int speed, int duration, int count, float randScale );
// JPW NERVE
void CG_MachineGunEjectBrass( centity_t *cent );
void CG_MachineGunEjectBrassNew( centity_t *cent );
// jpw
#define	DEBUGNAME(x) if(cg_debugEvents.integer){CG_Printf(x"\n");}
void Wolfcam_EntityEvent( centity_t *cent, vec3_t position ) {
	entityState_t		*es;
	int					event;
	vec3_t				dir;
	const char			*s;
	int					clientNum;
	clientInfo_t		*ci;
	char				tempStr[MAX_QPATH];
	bg_playerclass_t	*classInfo;
	bg_character_t		*character;
    //int *a; 
// JPW NERVE copied here for mg42 SFX event
	vec3_t				porg, gorg, norm;	// player/gun origin
	float				gdist;
// jpw
    int *a;

	static int		footstepcnt = 0;
	static int		splashfootstepcnt = 0;

	es = &cent->currentState;
	event = es->event & ~EV_EVENT_BITS;

	if ( cg_debugEvents.integer ) {
		CG_Printf( "time:%i ent:%3i  event:%3i ", cg.time, es->number, event );
	}

	if ( !event ) {
		DEBUGNAME("ZEROEVENT");
		return;
	}

	clientNum = es->clientNum;
	if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
		clientNum = 0;
	}

    // etpro BULLET_
    // a[2] es->eFlags == attacker
    // a[13] == victim

	ci = &cgs.clientinfo[ clientNum ];
	classInfo = CG_PlayerClassForClientinfo( ci, cent );
	character = CG_CharacterForClientinfo( ci, cent );

	switch ( event ) {
	//
	// movement generated events
	//
	case EV_FOOTSTEP:
		DEBUGNAME("EV_FOOTSTEP");
		if( es->eventParm != FOOTSTEP_TOTAL ) {
			if( es->eventParm ) {
				CG_StartFootStepSound( classInfo, es, cgs.media.footsteps[ es->eventParm ][footstepcnt] );
			} else {
				CG_StartFootStepSound( classInfo, es, cgs.media.footsteps[ character->animModelInfo->footsteps ][footstepcnt] );
			}
		}
		break;
	case EV_FOOTSPLASH:
		DEBUGNAME("EV_FOOTSPLASH");
		CG_StartFootStepSound( classInfo, es, cgs.media.footsteps[ FOOTSTEP_SPLASH ][splashfootstepcnt] );
		break;
	case EV_FOOTWADE:
		DEBUGNAME("EV_FOOTWADE");
		CG_StartFootStepSound( classInfo, es, cgs.media.footsteps[ FOOTSTEP_SPLASH ][splashfootstepcnt] );
		break;
	case EV_SWIM:
		DEBUGNAME("EV_SWIM");
		CG_StartFootStepSound( classInfo, es, cgs.media.footsteps[ FOOTSTEP_SPLASH ][footstepcnt] );
		break;

	case EV_FALL_SHORT:
		DEBUGNAME("EV_FALL_SHORT");
		if( es->eventParm != FOOTSTEP_TOTAL ) {
			if( es->eventParm ) {
				trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound[ es->eventParm ] );
			} else {
				trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound[ character->animModelInfo->footsteps ] );
			}
		}
		if ( clientNum == cg.predictedPlayerState.clientNum ) {
			// smooth landing z changes
			cg.landChange = -8;
			cg.landTime = cg.time;
		}
		break;

	case EV_FALL_DMG_10:
		DEBUGNAME("EV_FALL_DMG_10");
		if( es->eventParm != FOOTSTEP_TOTAL ) {
			if( es->eventParm ) {
				trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound[ es->eventParm ] );
			} else {
				trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound[ character->animModelInfo->footsteps ] );
			}
		}
		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landHurt );
		cent->pe.painTime = cg.time;	// don't play a pain sound right after this
		if ( clientNum == cg.predictedPlayerState.clientNum ) {
			// smooth landing z changes
			cg.landChange = -16;
			cg.landTime = cg.time;
		}
		break;
	case EV_FALL_DMG_15:
		DEBUGNAME("EV_FALL_DMG_15");
		if( es->eventParm != FOOTSTEP_TOTAL ) {
			if( es->eventParm ) {
				trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound[ es->eventParm ] );
			} else {
				trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound[ character->animModelInfo->footsteps ] );
			}
		}
		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landHurt );
		cent->pe.painTime = cg.time;	// don't play a pain sound right after this
		if ( clientNum == cg.predictedPlayerState.clientNum ) {
			// smooth landing z changes
			cg.landChange = -16;
			cg.landTime = cg.time;
		}
		break;
	case EV_FALL_DMG_25:
		DEBUGNAME("EV_FALL_DMG_25");
		if( es->eventParm != FOOTSTEP_TOTAL ) {
			if( es->eventParm ) {
				trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound[ es->eventParm ] );
			} else {
				trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound[ character->animModelInfo->footsteps ] );
			}
		}
		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landHurt );
		cent->pe.painTime = cg.time;	// don't play a pain sound right after this
		if ( clientNum == cg.predictedPlayerState.clientNum ) {
			// smooth landing z changes
			cg.landChange = -24;
			cg.landTime = cg.time;
		}
		break;
	case EV_FALL_DMG_50:
		DEBUGNAME("EV_FALL_DMG_50");
		if( es->eventParm != FOOTSTEP_TOTAL ) {
			if( es->eventParm ) {
				trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound[ es->eventParm ] );
			} else {
				trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound[ character->animModelInfo->footsteps ] );
			}
		}
		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landHurt );
		cent->pe.painTime = cg.time;	// don't play a pain sound right after this
		if ( clientNum == cg.predictedPlayerState.clientNum ) {
			// smooth landing z changes
			cg.landChange = -24;
			cg.landTime = cg.time;
		}
		break;
	case EV_FALL_NDIE:
		DEBUGNAME("EV_FALL_NDIE");
		if( es->eventParm != FOOTSTEP_TOTAL ) {
			if( es->eventParm ) {
				trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound[ es->eventParm ] );
			} else {
				trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound[ character->animModelInfo->footsteps ] );
			}
		}
		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landHurt );
		cent->pe.painTime = cg.time;	// don't play a pain sound right after this
		// splat
		break;
	
	case EV_EXERT1:
		DEBUGNAME("EV_EXERT1");
		trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*exert1.wav" ) );
		break;
	case EV_EXERT2:
		DEBUGNAME("EV_EXERT2");
		trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*exert2.wav" ) );
		break;
	case EV_EXERT3:
		DEBUGNAME("EV_EXERT3");
		trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*exert3.wav" ) );
		break;

	case EV_STEP_4:
	case EV_STEP_8:
	case EV_STEP_12:
	case EV_STEP_16:		// smooth out step up transitions
		DEBUGNAME("EV_STEP");
	{
		float	oldStep;
		int		delta;
		int		step;

		if ( clientNum != cg.predictedPlayerState.clientNum   ||  wolfcam_ent > -1) {
			break;
		}
		// if we are interpolating, we don't need to smooth steps
		if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ||
			cg_nopredict.integer 
#ifdef ALLOW_GSYNC
			|| cg_synchronousClients.integer 
#endif // ALLOW_GSYNC
			) {
			break;
		}
		// check for stepping up before a previous step is completed
		delta = cg.time - cg.stepTime;
		if (delta < STEP_TIME) {
			oldStep = cg.stepChange * (STEP_TIME - delta) / STEP_TIME;
		} else {
			oldStep = 0;
		}

		// add this amount
		step = 4 * (event - EV_STEP_4 + 1 );
		cg.stepChange = oldStep + step;
		if ( cg.stepChange > MAX_STEP_CHANGE ) {
			cg.stepChange = MAX_STEP_CHANGE;
		}
		cg.stepTime = cg.time;
		break;
	}

	case EV_JUMP:
		DEBUGNAME("EV_JUMP");
		trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );
		break;
	case EV_TAUNT:
		DEBUGNAME("EV_TAUNT");
		trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.wav" ) );
		break;
	case EV_WATER_TOUCH:
		DEBUGNAME("EV_WATER_TOUCH");
		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrInSound );
		break;
	case EV_WATER_LEAVE:
		DEBUGNAME("EV_WATER_LEAVE");
		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound );
		break;
	case EV_WATER_UNDER:
		DEBUGNAME("EV_WATER_UNDER");
		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound );
		if( cg.clientNum == es->number ) {
			cg.waterundertime = cg.time + HOLDBREATHTIME;
		}

//----(SA)	this fog stuff for underwater is really just a test for feasibility of creating the under-water effect that way.
//----(SA)	the related issues of load/savegames, death underwater, etc. are not handled at all.
//----(SA)	the actual problem, of course, is doing underwater stuff when the water is very turbulant and you can't simply
//----(SA)	do things based on the players head being above/below the water brushes top surface. (since the waves can potentially be /way/ above/below that)

		// DHM - Nerve :: causes problems in multiplayer...
		break;
	case EV_WATER_CLEAR:
		DEBUGNAME("EV_WATER_CLEAR");
		//trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.wav" ) );
		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound );
		if( es->eventParm )
			trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrGaspSound );
		break;

	case EV_ITEM_PICKUP:
	case EV_ITEM_PICKUP_QUIET:
		DEBUGNAME("EV_ITEM_PICKUP");
		{
			gitem_t	*item;
			int		index;

			index = es->eventParm;		// player predicted

			if ( index < 1 || index >= bg_numItems ) {
				break;
			}
			item = &bg_itemlist[ index ];

			if(event == EV_ITEM_PICKUP)	// not quiet
			{
				// powerups and team items will have a separate global sound, this one
				// will be played at prediction time
				if( item->giType == IT_TEAM) {
					trap_S_StartSound (NULL, es->number, CHAN_AUTO,	trap_S_RegisterSound( "sound/misc/w_pkup.wav", qfalse ) );
				} else {
					trap_S_StartSound (NULL, es->number, CHAN_AUTO,	trap_S_RegisterSound( item->pickup_sound, qfalse ) );
				}
			}

            
			// show icon and name on status bar
			if ( es->number == cg.snap->ps.clientNum   &&  wolfcam_ent < 0) {
				CG_ItemPickup( index );
			}

            if (wolfcam_ent > -1  &&  es->number == cgs.clientinfo[wolfcam_ent].clientNum)  //FIXME wolfcam double check
                CG_ItemPickup (index);
//----(SA)	draw the HUD items for a sec since this is a special item
/*			if ( item->giType == IT_KEY)
				cg.itemFadeTime = cg.time + 1000;*/

		}
		break;

	case EV_GLOBAL_ITEM_PICKUP:
		DEBUGNAME("EV_GLOBAL_ITEM_PICKUP");
		{
			gitem_t	*item;
			int		index;

			index = es->eventParm;		// player predicted

			if ( index < 1 || index >= bg_numItems ) {
				break;
			}
			item = &bg_itemlist[ index ];
			if( *item->pickup_sound ) {
				// powerup pickups are global
				//trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) );	// FIXME: precache
                trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound(item->pickup_sound, qfalse));  // wolfcam
			}

			// show icon and name on status bar
			if ( es->number == cg.snap->ps.clientNum  &&  wolfcam_ent < 0) {
				CG_ItemPickup( index );
			}
            if (wolfcam_ent > -1  &&  es->number == cgs.clientinfo[wolfcam_ent].clientNum) {
                CG_ItemPickup (index);
            }
		}
		break;

	//
	// weapon events
	//
	case EV_VENOM:
		DEBUGNAME("EV_VENOM");
//		CG_VenomFire( es, qfalse );
		break;

	case EV_WEAP_OVERHEAT:
		DEBUGNAME("EV_WEAP_OVERHEAT");

		// start weapon idle animation
		if(es->number == cg.snap->ps.clientNum  &&  wolfcam_ent < 0) {
			cg.predictedPlayerState.weapAnim = ( ( cg.predictedPlayerState.weapAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | PM_IdleAnimForWeapon(cg.snap->ps.weapon);
			cent->overheatTime = cg.time;	// used to make the barrels smoke when overheated
		}

        if (wolfcam_ent > -1  &&  es->number == cgs.clientinfo[wolfcam_ent].clientNum) {
            wolfcam_weapAnim = ( (wolfcam_weapAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | PM_IdleAnimForWeapon(cg_entities[cgs.clientinfo[wolfcam_ent].clientNum].currentState.weapon);  //FIXME wolfcam Wolfcam_IdleAnimForWeapon() ?
            //cent->overheatTime = cg.time;
            wolfcam_event_overheatTime = cg.time;
        }
        cent->overheatTime = cg.time;  //FIXME wolfcam just checking
		if( BG_PlayerMounted( es->eFlags ) ) {
			trap_S_StartSoundVControl( NULL, es->number, CHAN_AUTO, cgs.media.hWeaponHeatSnd, 255 );
		} else if( es->eFlags & EF_MOUNTEDTANK ) {
			if( cg_entities[cg_entities[cg_entities[ es->number ].tagParent].tankparent].currentState.density & 8 ) {
				trap_S_StartSoundVControl( NULL, es->number, CHAN_AUTO, cgs.media.hWeaponHeatSnd_2, 255 );
			} else {
				trap_S_StartSoundVControl( NULL, es->number, CHAN_AUTO, cgs.media.hWeaponHeatSnd, 255 );
			}
		} else if( cg_weapons[es->weapon].overheatSound ) {
			trap_S_StartSound (NULL, es->number, CHAN_AUTO, cg_weapons[es->weapon].overheatSound );
		}
		break;

// JPW NERVE
	case EV_SPINUP: 
		DEBUGNAME("EV_SPINUP");
			trap_S_StartSound (NULL, es->number, CHAN_AUTO, cg_weapons[es->weapon].spinupSound );
		break;
// jpw
	case EV_EMPTYCLIP:
		DEBUGNAME("EV_EMPTYCLIP");
        //Com_Printf ("EV_EMPTYCLIP\n");  // wolfcam
		break;

	case EV_FILL_CLIP:
		DEBUGNAME("EV_FILL_CLIP");
        if (wolfcam_ent > -1  &&  es->number == cgs.clientinfo[wolfcam_ent].clientNum)
            wolfcam_event_reloadTime = cg.time;

		if( cgs.clientinfo[cg.clientNum].skill[SK_LIGHT_WEAPONS] >= 2 && BG_isLightWeaponSupportingFastReload( es->weapon ) && cg_weapons[es->weapon].reloadFastSound )
			trap_S_StartSound (NULL, es->number, CHAN_WEAPON, cg_weapons[es->weapon].reloadFastSound );
		else if(cg_weapons[es->weapon].reloadSound)
			trap_S_StartSound (NULL, es->number, CHAN_WEAPON, cg_weapons[es->weapon].reloadSound ); // JPW NERVE following sherman's SP fix, should allow killing reload sound when player dies
		break;

// JPW NERVE play a sound when engineer fixes MG42
	case EV_MG42_FIXED:
		DEBUGNAME("EV_MG42_FIXED");
		//trap_S_StartSound(NULL,es->number,CHAN_WEAPON,cg_weapons[WP_MAUSER].reloadSound); // Arnout: needs updating
		break;
// jpw

	case EV_NOAMMO:
	case EV_WEAPONSWITCHED:
		DEBUGNAME("EV_NOAMMO");
        //FIXME wolfcam RaiseAnim for weapon??
		if((es->weapon != WP_GRENADE_LAUNCHER) &&
			(es->weapon != WP_GRENADE_PINEAPPLE) &&
			(es->weapon != WP_DYNAMITE) &&
			(es->weapon != WP_LANDMINE) &&
			(es->weapon != WP_SATCHEL) &&
			(es->weapon != WP_SATCHEL_DET) &&
			(es->weapon != WP_TRIPMINE) &&
			(es->weapon != WP_SMOKE_BOMB) &&
			(es->weapon != WP_AMMO) &&
			(es->weapon != WP_MEDKIT))
			trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.noAmmoSound );

		if( es->number == cg.snap->ps.clientNum  &&  wolfcam_ent < 0  &&  (
		    ( cg_noAmmoAutoSwitch.integer > 0 && !CG_WeaponSelectable( cg.weaponSelect ) ) ||
			es->weapon == WP_MORTAR_SET ||
			es->weapon == WP_MOBILE_MG42_SET ||
			es->weapon == WP_GRENADE_LAUNCHER ||
			es->weapon == WP_GRENADE_PINEAPPLE ||
			es->weapon == WP_DYNAMITE ||
			es->weapon == WP_SMOKE_MARKER ||
			es->weapon == WP_PANZERFAUST ||
			es->weapon == WP_ARTY ||
			es->weapon == WP_LANDMINE ||
			es->weapon == WP_SATCHEL ||
			es->weapon == WP_SATCHEL_DET ||
			es->weapon == WP_TRIPMINE ||
			es->weapon == WP_SMOKE_BOMB ||
			es->weapon == WP_AMMO ||
			es->weapon == WP_MEDKIT ) ) {
			CG_OutOfAmmoChange( event == EV_WEAPONSWITCHED ? qfalse : qtrue);
		}
		break;
	case EV_CHANGE_WEAPON:
		DEBUGNAME("EV_CHANGE_WEAPON");
        if (wolfcam_ent > -1  &&  es->number == cgs.clientinfo[wolfcam_ent].clientNum) {
            //CG_Printf ("^3EV_CHANGE WEAPON\n");
            //FIXME check for weapons
            a = (int *) es;
            //CG_Printf ("^3EV_CHANGE_WEAPON %d %d %d %d %d %d %d %d %d\n", cg.time, a[16], a[17], a[18], a[19], a[20], a[21], a[22], a[23]);
            Wolfcam_ReadNextSnapshot ();
            wolfcam_event_weaponSwitchTime = cg.time;
            wolfcam_event_newWeapon = 0;
            wolfcam_event_oldWeapon = es->weapon;
        }
		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound );
		break;
	case EV_CHANGE_WEAPON_2:
		DEBUGNAME("EV_CHANGE_WEAPON");

        if (wolfcam_ent > -1  &&  es->number == cgs.clientinfo[wolfcam_ent].clientNum) {
            CG_Printf ("^1EV_CHANGE_WEAPON_2\n");
            //FIXME check for weapons
            wolfcam_event_weaponSwitchTime = cg.time;  //FIXME wolfcam and reload??
            wolfcam_event_newWeapon = 0;  //
            wolfcam_event_oldWeapon = es->weapon;
        }
		trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound );

		if( es->number == cg.snap->ps.clientNum  &&  wolfcam_ent < 0) {
			int newweap = 0;

			// client will get this message if reloading while using an alternate weapon
			// client should voluntarily switch back to primary at that point
			switch(es->weapon) {
				case WP_FG42SCOPE:
					newweap = WP_FG42;
					break;
				case WP_GARAND_SCOPE:
					newweap = WP_GARAND;
					break;
				case WP_K43_SCOPE:
					newweap = WP_K43;
					break;
				default:
					break;
			}

			if( newweap ) {
				CG_FinishWeaponChange( es->weapon, newweap );  //FIXME wolfcam check if we need this
			}
		}
		break;
	
	case EV_FIRE_WEAPON_MOUNTEDMG42:
	case EV_FIRE_WEAPON_MG42:
        //if (wolfcam_ent > -1  &&  es->number == cgs.clientinfo[wolfcam_ent].clientNum)  //FIXME wolfcam double check if things are cent->currentState.clientNum or es->number
        //    wolfcam_event_fireWeaponTime = cg.time;  //FIXME wolfcam maybe not??
		VectorCopy(cent->currentState.pos.trBase, gorg);
		VectorCopy(cg.refdef_current->vieworg, porg);
		VectorSubtract(gorg, porg, norm);
		gdist = VectorNormalize(norm);
		if(gdist > 512 && gdist < 4096) {
			VectorMA(cg.refdef_current->vieworg, 64, norm, gorg);
			if( cg_entities[cg_entities[cg_entities[ cent->currentState.number ].tagParent].tankparent].currentState.density & 8 ) { // should we use a browning?
				trap_S_StartSoundEx( gorg, cent->currentState.number, CHAN_WEAPON, cgs.media.hWeaponEchoSnd_2, SND_NOCUT);
			} else {
				trap_S_StartSoundEx( gorg, cent->currentState.number, CHAN_WEAPON, cgs.media.hWeaponEchoSnd, SND_NOCUT);
			}
		}
		DEBUGNAME("EV_FIRE_WEAPON_MG42");
		CG_FireWeapon( cent );
		break;
	case EV_FIRE_WEAPON_AAGUN:
		DEBUGNAME("EV_FIRE_WEAPON_AAGUN");
		CG_FireWeapon( cent);
		break;
	case EV_FIRE_WEAPON:
	case EV_FIRE_WEAPONB:
		DEBUGNAME("EV_FIRE_WEAPON");
        //if (wolfcam_ent > -1  &&  es->number == cgs.clientinfo[wolfcam_ent].clientNum)
        if (wolfcam_ent > -1  &&  cent->currentState.clientNum == cgs.clientinfo[wolfcam_ent].clientNum) {
            wolfcam_event_fireWeaponTime = cg.time;  //FIXME wolfcam this ok?
            wolfcam_event_akimboFire = event == EV_FIRE_WEAPONB ? qtrue : qfalse;
        }
		if( wolfcam_ent < 0  &&  cent->currentState.clientNum == cg.snap->ps.clientNum && cg.snap->ps.eFlags & EF_ZOOMING ) // to stop airstrike sfx
			break;
		CG_FireWeapon( cent);
		if( event == EV_FIRE_WEAPONB )	// akimbo firing
			cent->akimboFire = qtrue;
		else
			cent->akimboFire = qfalse;
		break;
	case EV_FIRE_WEAPON_LASTSHOT:
        //FIXME wolfcam LastAttackAnimForWEapon
		DEBUGNAME("EV_FIRE_WEAPON_LASTSHOT");
		CG_FireWeapon( cent);
		break;

	case EV_NOFIRE_UNDERWATER:
		DEBUGNAME("EV_NOFIRE_UNDERWATER");
		if(cgs.media.noFireUnderwater)
			trap_S_StartSound (NULL, es->number, CHAN_WEAPON, cgs.media.noFireUnderwater);
		break;

	case EV_PLAYER_TELEPORT_IN:
        Com_Printf ("^6teleport in %d\n", cent->currentState.clientNum);
		break;

	case EV_PLAYER_TELEPORT_OUT:
        Com_Printf ("^6teleport out %d\n", cent->currentState.clientNum);
		break;

	case EV_ITEM_POP:
		break;
	case EV_ITEM_RESPAWN:
		break;

	case EV_GRENADE_BOUNCE:
		DEBUGNAME("EV_GRENADE_BOUNCE");

		// DYNAMITE // Gordon: or LANDMINE FIXME: change this? (mebe a metallic sound)
		if( es->weapon == WP_SATCHEL ) {
			trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.satchelbounce1 );
		} else if( es->weapon == WP_DYNAMITE ) {
			trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.dynamitebounce1 );
		} else if( es->weapon == WP_LANDMINE ) {
			trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landminebounce1 );
		} else {
		// GRENADES
			if( es->eventParm != FOOTSTEP_TOTAL ) {
				if ( rand() & 1 ) {
					trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.grenadebounce[ es->eventParm ][0] );
				} else {
					trap_S_StartSound( NULL, es->number, CHAN_AUTO,  cgs.media.grenadebounce[ es->eventParm ][1] );
				}
			}
		}
		break;

/*	case EV_FLAMEBARREL_BOUNCE:
		DEBUGNAME("EV_FLAMEBARREL_BOUNCE");
		if ( rand() & 1 ) {
			trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.fbarrelexp1 );
		} else {
			trap_S_StartSound (NULL, es->number, CHAN_AUTO,  cgs.media.fbarrelexp2 );
		}
		break;*/

	case EV_RAILTRAIL:
		CG_RailTrail( &cgs.clientinfo[ es->otherEntityNum2 ], es->origin2, es->pos.trBase, es->dmgFlags);	//----(SA)	added 'type' field
		break;

	//
	// missile impacts
	//
	case EV_MISSILE_HIT:
		DEBUGNAME("EV_MISSILE_HIT");
		ByteToDir( es->eventParm, dir );
		CG_MissileHitPlayer( cent, es->weapon, position, dir, es->otherEntityNum );
		if( es->weapon == WP_MORTAR_SET ) {
			if( !es->legsAnim ) {
				CG_MortarImpact( cent, position, 3, qtrue );
			} else {
				CG_MortarImpact( cent, position, -1, qtrue );
			}
		}
		break;

	case EV_MISSILE_MISS_SMALL:
		DEBUGNAME("EV_MISSILE_MISS");
		ByteToDir( es->eventParm, dir );
		CG_MissileHitWallSmall( es->weapon, 0, position, dir );
		break;

	case EV_MISSILE_MISS:
		DEBUGNAME("EV_MISSILE_MISS");
		ByteToDir( es->eventParm, dir );
		CG_MissileHitWall( es->weapon, 0, position, dir, 0 );	// (SA) modified to send missilehitwall surface parameters
		if( es->weapon == WP_MORTAR_SET ) {
			if( !es->legsAnim ) {
				CG_MortarImpact( cent, position, 3, qtrue );
			} else {
				CG_MortarImpact( cent, position, -1, qtrue );
			}
		}
		break;

	case EV_MISSILE_MISS_LARGE:
		DEBUGNAME("EV_MISSILE_MISS_LARGE");
		ByteToDir( es->eventParm, dir );
		if( es->weapon == WP_ARTY || es->weapon == WP_SMOKE_MARKER ) {
			CG_MissileHitWall( es->weapon, 0, position, dir, 0);	// (SA) modified to send missilehitwall surface parameters
		} else {
			CG_MissileHitWall( VERYBIGEXPLOSION, 0, position, dir, 0);	// (SA) modified to send missilehitwall surface parameters
		}
		break;

	case EV_MORTAR_IMPACT:
		DEBUGNAME("EV_MORTAR_IMPACT");
		CG_MortarImpact( cent, position, rand()%3, qfalse );
		break;
	case EV_MORTAR_MISS:
		DEBUGNAME("EV_MORTAR_MISS");
		CG_MortarMiss( cent, position );
		break;

	case EV_MG42BULLET_HIT_WALL:
		DEBUGNAME("EV_MG42BULLET_HIT_WALL");
		ByteToDir( es->eventParm, dir );
        if (wolfcam_gameVersion == WOLFCAM_ETPRO) {
            a = (int *) es;
            CG_Bullet (es->pos.trBase, a[2], dir, qfalse, ENTITYNUM_WORLD, es->otherEntityNum2, es->origin2[0], es->effect1Time);
        } else
            CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD, es->otherEntityNum2, es->origin2[0], es->effect1Time );
		break;

	case EV_MG42BULLET_HIT_FLESH:
		DEBUGNAME("EV_MG42BULLET_HIT_FLESH");
        if (wolfcam_gameVersion == WOLFCAM_ETPRO) {
            a = (int *) es;
            CG_Bullet (es->pos.trBase, a[2], dir, qtrue, a[13], es->otherEntityNum2, es->origin[2], 0);
            if (wolfcam_ent > -1) {
                if (cgs.clientinfo[wolfcam_ent].clientNum == a[13])
                    wolfcam_bulletDamageTime = cg.time + DAMAGE_TIME;
            }
        } else
            CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm, es->otherEntityNum2, 0, es->effect1Time);
		break;


	case EV_BULLET_HIT_WALL:
		DEBUGNAME("EV_BULLET_HIT_WALL");
		ByteToDir( es->eventParm, dir );
        if (wolfcam_gameVersion == WOLFCAM_ETPRO) {
            a = (int *) es;
            CG_Bullet (es->pos.trBase, a[2], dir, qfalse, ENTITYNUM_WORLD, es->otherEntityNum2, es->origin[2], 0);  //FIXME wolfcam didn't even check 
        } else
            CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD, es->otherEntityNum2, es->origin2[0], 0 );
		break;

	case EV_BULLET_HIT_FLESH:
		DEBUGNAME("EV_BULLET_HIT_FLESH");
        if (wolfcam_gameVersion == WOLFCAM_ETPRO) {
            a = (int *) es;
            CG_Bullet (es->pos.trBase, a[2], dir, qtrue, a[13], es->otherEntityNum2, 0, 0);
            if (wolfcam_ent > -1) {
                if (cgs.clientinfo[wolfcam_ent].clientNum == a[13])
                    wolfcam_bulletDamageTime = cg.time;
            }
            //FIXME wolfcam damage kick 
            //FIXME wolfcam check other EV_BULLET_*
        }
        else
            CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm, es->otherEntityNum2, 0, 0);
		break;

	case EV_POPUPBOOK:
	case EV_POPUP:
	case EV_GIVEPAGE:
        //CG_Printf ("^1....hm...\n");
		break;

	case EV_GENERAL_SOUND:
		DEBUGNAME("EV_GENERAL_SOUND");
		// Ridah, check for a sound script
		s = CG_ConfigString( CS_SOUNDS + es->eventParm );
        //CG_Printf ("EV_GENERAL_SOUND: %s\n", s);
		if( !strstr( s, ".wav" ) ) {
			if( CG_SoundPlaySoundScript( s, NULL, es->number, qfalse ) ) {
				break;
			}
			// try with .wav
			Q_strncpyz( tempStr, s, sizeof(tempStr) );
			Q_strcat( tempStr, sizeof(tempStr), ".wav" );
			s = tempStr;
		}

		// done.
		if ( cgs.gameSounds[ es->eventParm ] ) {
			// xkan, 10/31/2002 - crank up the volume 
			trap_S_StartSoundVControl( NULL, es->number, CHAN_VOICE, cgs.gameSounds[ es->eventParm ], 255 );
		} else {
			s = CG_ConfigString( CS_SOUNDS + es->eventParm );
			// xkan, 10/31/2002 - crank up the volume 
			trap_S_StartSoundVControl( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, s ), 255 );
		}
		break;

	case EV_FX_SOUND:
		{
			sfxHandle_t sound;

			DEBUGNAME("EV_FX_SOUND");

			sound = random()*fxSounds[ es->eventParm ].max;

			if( fxSounds[ es->eventParm ].sound[ sound ] == -1 ) {
				fxSounds[ es->eventParm ].sound[ sound ] = trap_S_RegisterSound( fxSounds[ es->eventParm ].soundfile[ sound ], qfalse );
			}

			sound = fxSounds[ es->eventParm ].sound[ sound ];

			trap_S_StartSoundVControl( NULL, es->number, CHAN_VOICE, sound, 255 );
		}
		break;
	case EV_GENERAL_SOUND_VOLUME:
		{
			int sound = es->eventParm;
			int volume = es->onFireStart;

			DEBUGNAME("EV_GENERAL_SOUND_VOLUME");
			// Ridah, check for a sound script
			s = CG_ConfigString( CS_SOUNDS + sound );
			if( !strstr( s, ".wav" ) ) {
				if( CG_SoundPlaySoundScript( s, NULL, es->number, qfalse ) ) {
					break;
				}
				// try with .wav
				Q_strncpyz( tempStr, s, sizeof(tempStr) );
				Q_strcat( tempStr, sizeof(tempStr), ".wav" );
				s = tempStr;
			}
			// done.
			if ( cgs.gameSounds[ sound ] ) {
				trap_S_StartSoundVControl( NULL, es->number, CHAN_VOICE, cgs.gameSounds[ sound ], volume );
			} else {
				s = CG_ConfigString( CS_SOUNDS + sound );
				trap_S_StartSoundVControl( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, s ), volume );
			}
		}
		break;

		
	case EV_GLOBAL_TEAM_SOUND:
		DEBUGNAME("EV_GLOBAL_TEAM_SOUND");
		if( cgs.clientinfo[ cg.snap->ps.clientNum ].team != es->teamNum   &&  wolfcam_ent < 0) {
			break;
		}
        if (wolfcam_ent > -1  &&  cgs.clientinfo[wolfcam_ent].team != es->teamNum)
            break;
	case EV_GLOBAL_SOUND:	// play from the player's head so it never diminishes
		DEBUGNAME("EV_GLOBAL_SOUND");
		// Ridah, check for a sound script
		s = CG_ConfigString( CS_SOUNDS + es->eventParm );
		if( !strstr( s, ".wav" ) ) {
			if( CG_SoundPlaySoundScript( s, NULL, -1, qtrue ) ) {
				break;
			}

			// try with .wav
			Q_strncpyz( tempStr, s, sizeof(tempStr) );
			Q_strcat( tempStr, sizeof(tempStr), ".wav" );
			s = tempStr;
		}

        if (wolfcam_ent < 0) {  //FIXME wolfcam don't know about this shit
            if ( cgs.gameSounds[ es->eventParm ] ) {
                trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] );
            } else {
                s = CG_ConfigString( CS_SOUNDS + es->eventParm );
                trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, CG_CustomSound( es->number, s ) );
            }
        } else { 
            if (cgs.gameSounds[es->eventParm]) 
                trap_S_StartSound( NULL, cgs.clientinfo[wolfcam_ent].clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] );
            else {
                s = CG_ConfigString( CS_SOUNDS + es->eventParm );
                trap_S_StartSound( NULL, cgs.clientinfo[wolfcam_ent].clientNum, CHAN_AUTO, CG_CustomSound( es->number, s ) );
            }
        }
		break;

	// DHM - Nerve
	case EV_GLOBAL_CLIENT_SOUND:
		DEBUGNAME("EV_GLOBAL_CLIENT_SOUND");

		if ( cg.snap->ps.clientNum == es->teamNum  &&  wolfcam_ent < 0) {
			s = CG_ConfigString( CS_SOUNDS + es->eventParm );
			if ( !strstr( s, ".wav" ) ) {
				if( CG_SoundPlaySoundScript( s, NULL, -1, (es->effect1Time ? qfalse : qtrue) ) ) {
					break;
				}
				// try with .wav
				Q_strncpyz( tempStr, s, sizeof(tempStr) );
				Q_strcat( tempStr, sizeof(tempStr), ".wav" );
				s = tempStr;
			}
			// done.
			if ( cgs.gameSounds[ es->eventParm ] ) {
				trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] );
			} else {
				s = CG_ConfigString( CS_SOUNDS + es->eventParm );
				trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, CG_CustomSound( es->number, s ) );
			}
		} else if (wolfcam_ent > -1  &&  cgs.clientinfo[wolfcam_ent].clientNum == es->teamNum) {
            s = CG_ConfigString( CS_SOUNDS + es->eventParm );
            if ( !strstr( s, ".wav" ) ) {
                if( CG_SoundPlaySoundScript( s, NULL, -1, (es->effect1Time ? qfalse : qtrue) ) ) {
                    break;
                }
                // try with .wav                                                                                                                                          
                Q_strncpyz( tempStr, s, sizeof(tempStr) );
                Q_strcat( tempStr, sizeof(tempStr), ".wav" );
                s = tempStr;
            }
            // done.                                                                                                                                                      
            if ( cgs.gameSounds[ es->eventParm ] ) {
                trap_S_StartSound (NULL, cgs.clientinfo[wolfcam_ent].clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] );
            } else {
                s = CG_ConfigString( CS_SOUNDS + es->eventParm );
                trap_S_StartSound (NULL, cgs.clientinfo[wolfcam_ent].clientNum, CHAN_AUTO, CG_CustomSound( es->number, s ) );
            }
        }

		break;
	// dhm - end

	case EV_PAIN:
		// local player sounds are triggered in CG_CheckLocalSounds,
		// so ignore events on the player
		DEBUGNAME("EV_PAIN");
        if (wolfcam_ent > -1  &&  cent->currentState.number == cgs.clientinfo[wolfcam_ent].clientNum) {
            wolfcam_health = es->eventParm;
        }
		if ( cent->currentState.number != cg.snap->ps.clientNum  &&  wolfcam_ent < 0) {
			CG_PainEvent( cent, es->eventParm, qfalse );
		}
        if (wolfcam_ent > -1  &&  cent->currentState.number != cgs.clientinfo[wolfcam_ent].clientNum)
            CG_PainEvent (cent, es->eventParm, qfalse);
		break;

	case EV_CROUCH_PAIN:
		// local player sounds are triggered in CG_CheckLocalSounds,
		// so ignore events on the player
		DEBUGNAME("EV_PAIN");
        if (wolfcam_ent > -1  &&  cent->currentState.number == cgs.clientinfo[wolfcam_ent].clientNum) {
            wolfcam_health = es->eventParm;
        }
		if ( cent->currentState.number != cg.snap->ps.clientNum  &&  wolfcam_ent < 0) {
			CG_PainEvent( cent, es->eventParm, qtrue );
		}
        if (wolfcam_ent > -1  &&  cent->currentState.number != cgs.clientinfo[wolfcam_ent].clientNum)
            CG_PainEvent (cent, es->eventParm, qtrue);
		break;

	case EV_DEATH1:
	case EV_DEATH2:
	case EV_DEATH3:
		DEBUGNAME("EV_DEATHx");
		trap_S_StartSound( NULL, es->number, CHAN_VOICE, 
				CG_CustomSound( es->number, va("*death%i.wav", event - EV_DEATH1 + 1) ) );
		break;


	case EV_OBITUARY:
		DEBUGNAME("EV_OBITUARY");
		Wolfcam_Obituary( es );
		break;

	// JPW NERVE -- swiped from SP/Sherman
	case EV_STOPSTREAMINGSOUND:
		DEBUGNAME("EV_STOPLOOPINGSOUND");
//		trap_S_StopStreamingSound( es->number );
		trap_S_StartSoundEx( NULL, es->number, CHAN_WEAPON, 0, SND_CUTOFF_ALL );	// kill weapon sound (could be reloading)
		break;

	case EV_LOSE_HAT:
		DEBUGNAME("EV_LOSE_HAT");
		ByteToDir( es->eventParm, dir );
		CG_LoseHat(cent, dir);
		break;

	case EV_GIB_PLAYER:
		DEBUGNAME("EV_GIB_PLAYER");
		trap_S_StartSound( es->pos.trBase, -1, CHAN_AUTO, cgs.media.gibSound );
		ByteToDir( es->eventParm, dir );
		CG_GibPlayer( cent, cent->lerpOrigin, dir );
		break;

	case EV_STOPLOOPINGSOUND:
		DEBUGNAME("EV_STOPLOOPINGSOUND");
		es->loopSound = 0;
		break;

	case EV_DEBUG_LINE:
		DEBUGNAME("EV_DEBUG_LINE");
		CG_Beam( cent );
		break;

	// Rafael particles
	case EV_SMOKE:
		DEBUGNAME("EV_SMOKE");
		if (cent->currentState.density == 3) {
			CG_ParticleSmoke (cgs.media.smokePuffShaderdirty, cent);
		} else if (!(cent->currentState.density)) {
			CG_ParticleSmoke (cgs.media.smokePuffShader, cent);
		} else {
			CG_ParticleSmoke (cgs.media.smokePuffShader, cent);
		}
		break;

	case EV_FLAMETHROWER_EFFECT:
				CG_FireFlameChunks( cent, cent->currentState.origin, cent->currentState.apos.trBase, 0.6, 2 );
		break;

	case EV_DUST:
		CG_ParticleDust (cent, cent->currentState.origin, cent->currentState.angles);
		break;

	case EV_RUMBLE_EFX:
		{
			float	pitch, yaw;
			pitch = cent->currentState.angles[0];
			yaw = cent->currentState.angles[1];
			CG_RumbleEfx ( pitch, yaw );
		}
		break;

	case EV_CONCUSSIVE:
		CG_Concussive (cent);
		break;

	case EV_EMITTER:
		{
			localEntity_t	*le;
			le = CG_AllocLocalEntity();
			le->leType = LE_EMITTER;
			le->startTime = cg.time;
			le->endTime = le->startTime + 20000;
			le->pos.trType = TR_STATIONARY;
			VectorCopy( cent->currentState.origin, le->pos.trBase );
			VectorCopy( cent->currentState.origin2, le->angles.trBase );
			le->ownerNum = 0;
		}
		break;

	case EV_OILPARTICLES:
		CG_Particle_OilParticle (cgs.media.oilParticle, cent->currentState.origin, cent->currentState.origin2, cent->currentState.time, cent->currentState.density);
		break;
	case EV_OILSLICK:
		CG_Particle_OilSlick (cgs.media.oilSlick, cent);
		break;
	case EV_OILSLICKREMOVE:
		CG_OilSlickRemove (cent);
		break;

	case EV_MG42EFX:
		CG_MG42EFX (cent);
		break;
	
	case EV_SPARKS_ELECTRIC:
	case EV_SPARKS:
		{
			int numsparks;
			int	i;
			int	duration;
			float	x,y;
			float	speed;
			vec3_t	source, dest;

			if (!(cent->currentState.density))
				cent->currentState.density = 1;
			numsparks = rand()%cent->currentState.density;
			duration = cent->currentState.frame;
			x = cent->currentState.angles2[0];
			y = cent->currentState.angles2[1];
			speed = cent->currentState.angles2[2];

			if (!numsparks)
				numsparks = 1;
			for (i=0; i<numsparks; i++)
			{
				
				if (event == EV_SPARKS_ELECTRIC)
				{
					VectorCopy (cent->currentState.origin, source);
				
					VectorCopy (source, dest);
					dest[0] += ((rand()&31)-16);
					dest[1] += ((rand()&31)-16);
					dest[2] += ((rand()&31)-16);

					CG_Tracer (source, dest, 1);
				}
				else
					CG_ParticleSparks (cent->currentState.origin, cent->currentState.angles, duration, x, y, speed);
				
			}
			
		}
		break;

	case EV_GUNSPARKS:
		{
			int	numsparks;
			int	speed;
			//int	count;

			numsparks = cent->currentState.density;
			speed = cent->currentState.angles2[2];
			
			CG_AddBulletParticles( cent->currentState.origin, cent->currentState.angles, speed, 800, numsparks, 1.0f ); 
				
		}
		break;

	// Rafael snow pvs check
	case EV_SNOW_ON:
		CG_SnowLink (cent, qtrue);
		break;

	case EV_SNOW_OFF:
		CG_SnowLink (cent, qfalse);
		break;

	
	case EV_SNOWFLURRY:
		CG_ParticleSnowFlurry (cgs.media.snowShader, cent);
		break;

	// for func_exploding
	case EV_EXPLODE:
		DEBUGNAME("EV_EXPLODE");
		ByteToDir( es->eventParm, dir );
		CG_Explode(cent, position, dir, 0);
		break;

	case EV_RUBBLE:
		DEBUGNAME("EV_RUBBLE");
		ByteToDir( es->eventParm, dir );
		CG_Rubble(cent, position, dir, 0);
		break;

		// for target_effect
	case EV_EFFECT:
		DEBUGNAME("EV_EFFECT");
		ByteToDir( es->eventParm, dir );
		CG_Effect(cent, position, dir);
		break;

	case EV_MORTAREFX:	// mortar firing
		DEBUGNAME("EV_MORTAREFX");
		CG_MortarEFX (cent);
		break;

	case EV_SHARD:
		ByteToDir( es->eventParm, dir );
		CG_Shard(cent, position, dir);
		break;

	case EV_JUNK:
		ByteToDir (es->eventParm, dir);
		{
			int i;
			int	rval;

			rval = rand()%3 + 3;

			for (i=0; i<rval; i++)
				CG_ShardJunk (cent, position, dir);
		}
		break;

	case EV_DISGUISE_SOUND:
		trap_S_StartSound( NULL, cent->currentState.number, CHAN_WEAPON, cgs.media.uniformPickup );
		break;
	case EV_BUILDDECAYED_SOUND:
		trap_S_StartSound( cent->lerpOrigin, cent->currentState.number, CHAN_AUTO, cgs.media.buildDecayedSound );
		break;

	// Gordon: debris test
	case EV_DEBRIS:
		CG_Debris( cent, position, cent->currentState.origin2 );
		break;
	// ===================

	case EV_SHAKE:
        //FIXME wolfcam cg.snap->ps.origin
		{
			vec3_t v;
			float len;
			
			DEBUGNAME("EV_SHAKE");

			VectorSubtract( cg.snap->ps.origin, cent->lerpOrigin, v );
			len = VectorLength (v);

			if(len > cent->currentState.onFireStart) {
				break;
			}

			len = 1.0f - (len / (float)cent->currentState.onFireStart);
			len = min(1.f, len);

			CG_StartShakeCamera( len );  //FIXME wolfcam
		}

		break;

	case EV_ALERT_SPEAKER:
		DEBUGNAME("EV_ALERT_SPEAKER");
        //CG_Printf ("^3EV_ALERT_SPEAKER\n");
		switch( cent->currentState.otherEntityNum2 )
		{
		case 1:		CG_UnsetActiveOnScriptSpeaker( cent->currentState.otherEntityNum );	break;
		case 2:		CG_SetActiveOnScriptSpeaker( cent->currentState.otherEntityNum );	break;
		case 0:
		default:	CG_ToggleActiveOnScriptSpeaker( cent->currentState.otherEntityNum );	break;
		}
		break;

	case EV_POPUPMESSAGE:
		{
			const char* str = CG_GetPMItemText( cent );
			qhandle_t shader = CG_GetPMItemIcon( cent );
            //a = (int *) es;
            //CG_Printf ("^3EV_POPUPMESSAGE: %d %d %d %d %d %d %d %d\n",
            //           a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
			if( str ) {
				CG_AddPMItem( cent->currentState.effect1Time, str, shader );
			}
			CG_PlayPMItemSound( cent );
		}
		break;

	case EV_AIRSTRIKEMESSAGE:
		{
			const char* wav = NULL;

            if (wolfcam_ent > 0)
                break;

			switch( cent->currentState.density ) {
				case 0: // too many called
					if( cgs.clientinfo[ cg.snap->ps.clientNum ].team == TEAM_AXIS ) {
						wav = "axis_hq_airstrike_denied";
					} else {
						wav = "allies_hq_airstrike_denied";
					}
					break;
				case 1: // aborting can't see target
					if( cgs.clientinfo[ cg.snap->ps.clientNum ].team == TEAM_AXIS ) {
						wav = "axis_hq_airstrike_abort";
					} else {
						wav = "allies_hq_airstrike_abort";
					}
					break;
				case 2: // firing for effect
					if( cgs.clientinfo[ cg.snap->ps.clientNum ].team == TEAM_AXIS ) {
						wav = "axis_hq_airstrike";
					} else {
						wav = "allies_hq_airstrike";
					}
					break;
			}

			if( wav ) {
				CG_SoundPlaySoundScript( wav, NULL, -1, (es->effect1Time ? qfalse : qtrue) );
			}
		}
		break;

	case EV_ARTYMESSAGE: 
		{
			const char* wav = NULL;

            if (wolfcam_ent > 0)
                break;

			switch( cent->currentState.density ) {
				case 0: // too many called
					if( cgs.clientinfo[ cg.snap->ps.clientNum ].team == TEAM_AXIS ) {
						wav = "axis_hq_ffe_denied";
					} else {
						wav = "allies_hq_ffe_denied";
					}
					break;
				case 1: // aborting can't see target
					if( cgs.clientinfo[ cg.snap->ps.clientNum ].team == TEAM_AXIS ) {
						wav = "axis_hq_ffe_abort";
					} else {
						wav = "allies_hq_ffe_abort";
					}
					break;
				case 2: // firing for effect
					if( cgs.clientinfo[ cg.snap->ps.clientNum ].team == TEAM_AXIS ) {
						wav = "axis_hq_ffe";
					} else {
						wav = "allies_hq_ffe";
					}
					break;
			}

			if( wav ) {
				CG_SoundPlaySoundScript( wav, NULL, -1, (es->effect1Time ? qfalse : qtrue) );
			}
		}
		break;

	case EV_MEDIC_CALL:  // 129
		switch( cgs.clientinfo[ cent->currentState.number ].team ) {
			case TEAM_AXIS:
				trap_S_StartSound( NULL, cent->currentState.number, CHAN_AUTO, cgs.media.sndMedicCall[0] );
				break;
			case TEAM_ALLIES:
				trap_S_StartSound( NULL, cent->currentState.number, CHAN_AUTO, cgs.media.sndMedicCall[1] );
				break;
			default: // shouldn't happen
				break;
		}

		break;

	default: 
        {
            qboolean handled = qfalse;
            if (wolfcam_gameVersion == WOLFCAM_ETPRO) {
            
                switch (event) {
                case 130:  // headshot EV_SHOT_HEAD
                case 131:  // body shot EV_SHOT_BODY
                case 132:  // teamate shot EV_SHOT_TEAMMATE
                    handled = qtrue;
                    break;
                default:
                    break;
                }
                if (wolfcam_debugErrors.integer  &&  !handled)
                    CG_Printf ("Unknown event: %i\n", event);
                break;
            }
        }
	}

	
	{
		int	rval;

		rval = rand()&3;
				
		if (splashfootstepcnt != rval)
			splashfootstepcnt = rval;
		else
			splashfootstepcnt++;
		
		if (splashfootstepcnt > 3)
			splashfootstepcnt = 0;
	

		if (footstepcnt != rval)
			footstepcnt = rval;
		else
			footstepcnt++;

		if (footstepcnt > 3)
			footstepcnt = 0;
	}
}
