937 lines
25 KiB
C
937 lines
25 KiB
C
/*
|
|
===========================================================================
|
|
Copyright (C) 1999-2005 Id Software, Inc.
|
|
Copyright (C) 2007 HermitWorks Entertainment Corporation
|
|
|
|
This file is part of the Space Trader source code.
|
|
|
|
The Space Trader source code is free software; you can redistribute it
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
or (at your option) any later version.
|
|
|
|
The Space Trader source code is distributed in the hope that it will be
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with the Space Trader source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "cg_local.h"
|
|
|
|
// cg_event.c -- handle entity events at snapshot or playerstate transitions
|
|
|
|
// for the voice chats
|
|
#include "../ui/menudef.h"
|
|
//==========================================================================
|
|
|
|
|
|
//==========================================================================
|
|
|
|
/*
|
|
===============
|
|
CG_UseItem
|
|
===============
|
|
*/
|
|
static void CG_UseItem( centity_t *cent ) {
|
|
int itemNum;
|
|
entityState_t *es;
|
|
|
|
es = ¢->currentState;
|
|
|
|
itemNum = (es->event & ~EV_EVENT_BITS) - EV_USE_ITEM0;
|
|
if ( itemNum < 0 || itemNum > HI_NUM_HOLDABLE ) {
|
|
itemNum = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
CG_ItemPickup
|
|
|
|
A new item was picked up this frame
|
|
================
|
|
*/
|
|
static void CG_ItemPickup( int itemNum ) {
|
|
cg.itemPickup = itemNum;
|
|
cg.itemPickupTime = cg.time;
|
|
cg.itemPickupBlendTime = cg.time;
|
|
// see if it should be the grabbed weapon
|
|
if ( bg_itemlist[itemNum].giType == IT_WEAPON ) {
|
|
// select it immediately
|
|
if ( cg_autoswitch.integer && bg_itemlist[itemNum].giTag > cg.weaponSelect && bg_itemlist[itemNum].giTag != WP_GRENADE &&
|
|
cg.snap->ps.weaponTime <= 0 ) {
|
|
cg.weaponSelectTime = cg.time;
|
|
cg.weaponSelect = bg_itemlist[itemNum].giTag;
|
|
}
|
|
}
|
|
switch( bg_itemlist[itemNum].giType ) {
|
|
case IT_ARMOR:
|
|
trap_Cmd_ExecuteText( EXEC_NOW, va("st_cp T_Shield_Pickup stash %d",bg_itemlist[itemNum].quantity) );
|
|
break;
|
|
case IT_HEALTH:
|
|
trap_Cmd_ExecuteText( EXEC_NOW, va("st_cp T_Health_Pickup stash %d",bg_itemlist[itemNum].quantity) );
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
CG_PainEvent
|
|
|
|
Also called by playerstate transition
|
|
================
|
|
*/
|
|
void CG_PainEvent( centity_t *cent, int health ) {
|
|
char *snd;
|
|
|
|
// don't do more than two pain sounds a second
|
|
if ( cg.time - cent->pe.painTime < 500 ) {
|
|
return;
|
|
}
|
|
|
|
if ( health < 25 ) {
|
|
snd = "*pain25_1.ogg";
|
|
} else if ( health < 50 ) {
|
|
snd = "*pain50_1.ogg";
|
|
} else if ( health < 75 ) {
|
|
snd = "*pain75_1.ogg";
|
|
} else {
|
|
snd = "*pain100_1.ogg";
|
|
}
|
|
trap_S_StartSound( NULL, cent->currentState.number, CHAN_VOICE,
|
|
CG_CustomSound( cent->currentState.number, snd ) );
|
|
|
|
// save pain time for programitic twitch animation
|
|
cent->pe.painTime = cg.time;
|
|
cent->pe.painDirection ^= 1;
|
|
}
|
|
|
|
/*
|
|
=============
|
|
CG_Obituary
|
|
=============
|
|
*/
|
|
static void CG_Obituary( entityState_t *ent ) {
|
|
int mod;
|
|
int target, attacker;
|
|
char *message;
|
|
char *message2;
|
|
const char *targetInfo;
|
|
const char *attackerInfo;
|
|
char targetName[32];
|
|
char attackerName[32];
|
|
gender_t gender;
|
|
clientInfo_t *ci;
|
|
|
|
target = ent->otherEntityNum;
|
|
attacker = ent->otherEntityNum2;
|
|
mod = ent->eventParm;
|
|
|
|
if ( target < 0 || target >= MAX_CLIENTS ) {
|
|
CG_Error( "CG_Obituary: target out of range" );
|
|
}
|
|
ci = &cgs.clientinfo[target];
|
|
|
|
if ( attacker < 0 || attacker >= MAX_CLIENTS ) {
|
|
attacker = ENTITYNUM_WORLD;
|
|
attackerInfo = NULL;
|
|
} else {
|
|
attackerInfo = CG_ConfigString( CS_PLAYERS + attacker );
|
|
}
|
|
|
|
targetInfo = CG_ConfigString( CS_PLAYERS + target );
|
|
if ( !targetInfo ) {
|
|
return;
|
|
}
|
|
Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof(targetName) - 2);
|
|
strcat( targetName, S_COLOR_WHITE );
|
|
|
|
message2 = "";
|
|
|
|
// check for single client messages
|
|
|
|
switch( mod ) {
|
|
case MOD_SUICIDE:
|
|
message = "suicides";
|
|
break;
|
|
case MOD_FALLING:
|
|
message = "cratered";
|
|
break;
|
|
case MOD_CRUSH:
|
|
message = "was squished";
|
|
break;
|
|
case MOD_WATER:
|
|
message = "sank like a rock";
|
|
break;
|
|
case MOD_SLIME:
|
|
message = "melted";
|
|
break;
|
|
case MOD_LAVA:
|
|
message = "does a back flip into the lava";
|
|
break;
|
|
case MOD_TARGET_LASER:
|
|
message = "saw the light";
|
|
break;
|
|
case MOD_TRIGGER_HURT:
|
|
message = "was in the wrong place";
|
|
break;
|
|
default:
|
|
message = NULL;
|
|
break;
|
|
}
|
|
|
|
if (attacker == target) {
|
|
gender = ci->gender;
|
|
switch (mod) {
|
|
#ifdef MISSIONPACK
|
|
case MOD_KAMIKAZE:
|
|
message = "goes out with a bang";
|
|
break;
|
|
#endif
|
|
case MOD_GRENADE_SPLASH:
|
|
if ( gender == GENDER_FEMALE )
|
|
message = "tripped on her own grenade";
|
|
else if ( gender == GENDER_NEUTER )
|
|
message = "tripped on its own grenade";
|
|
else
|
|
message = "tripped on his own grenade";
|
|
break;
|
|
case MOD_ROCKET_SPLASH:
|
|
if ( gender == GENDER_FEMALE )
|
|
message = "blew herself up";
|
|
else if ( gender == GENDER_NEUTER )
|
|
message = "blew itself up";
|
|
else
|
|
message = "blew himself up";
|
|
break;
|
|
#ifdef MISSIONPACK
|
|
case MOD_PROXIMITY_MINE:
|
|
if( gender == GENDER_FEMALE ) {
|
|
message = "found her prox mine";
|
|
} else if ( gender == GENDER_NEUTER ) {
|
|
message = "found it's prox mine";
|
|
} else {
|
|
message = "found his prox mine";
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
if ( gender == GENDER_FEMALE )
|
|
message = "killed herself";
|
|
else if ( gender == GENDER_NEUTER )
|
|
message = "killed itself";
|
|
else
|
|
message = "killed himself";
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (message) {
|
|
CG_Printf( "%s %s.\n", targetName, message);
|
|
return;
|
|
}
|
|
|
|
// check for kill messages from the current clientNum
|
|
if ( attacker == cg.snap->ps.clientNum ) {
|
|
char *s;
|
|
|
|
if ( cgs.gametype < GT_TEAM ) {
|
|
s = va("You got %s\n%s place with %i", targetName,
|
|
fn( (cg.snap->ps.persistant[PERS_RANK] & ~RANK_TIED_FLAG) + 1, FN_RANK ),
|
|
cg.snap->ps.persistant[PERS_SCORE] );
|
|
} else {
|
|
s = va("%s got you", targetName );
|
|
}
|
|
trap_Cmd_ExecuteText( EXEC_NOW, va("st_cp \"%s\"", s) );
|
|
}
|
|
|
|
// check for double client messages
|
|
if ( !attackerInfo ) {
|
|
attacker = ENTITYNUM_WORLD;
|
|
strcpy( attackerName, "noname" );
|
|
} else {
|
|
Q_strncpyz( attackerName, Info_ValueForKey( attackerInfo, "n" ), sizeof(attackerName) - 2);
|
|
strcat( attackerName, S_COLOR_WHITE );
|
|
// check for kill messages about the current clientNum
|
|
if ( target == cg.snap->ps.clientNum ) {
|
|
Q_strncpyz( cg.killerName, attackerName, sizeof( cg.killerName ) );
|
|
}
|
|
}
|
|
|
|
if ( attacker != ENTITYNUM_WORLD ) {
|
|
switch (mod) {
|
|
case MOD_GRAPPLE:
|
|
message = "was caught by";
|
|
break;
|
|
case MOD_GAUNTLET:
|
|
message = "was pummeled by";
|
|
break;
|
|
case MOD_MACHINEGUN:
|
|
message = "was machinegunned by";
|
|
break;
|
|
case MOD_SHOTGUN:
|
|
message = "was shotgunned into a fine mist by";
|
|
break;
|
|
case MOD_GRENADE:
|
|
message = "ate";
|
|
message2 = "'s grenade";
|
|
break;
|
|
case MOD_GRENADE_SPLASH:
|
|
message = "was shredded by";
|
|
message2 = "'s shrapnel";
|
|
break;
|
|
case MOD_ROCKET:
|
|
message = "ate";
|
|
message2 = "'s rocket";
|
|
break;
|
|
case MOD_ROCKET_SPLASH:
|
|
message = "almost dodged";
|
|
message2 = "'s rocket";
|
|
break;
|
|
case MOD_TELEFRAG:
|
|
message = "tried to invade";
|
|
message2 = "'s personal space";
|
|
break;
|
|
case MOD_HIGHCAL:
|
|
message = "thought he was immune to bullets from";
|
|
message2 = "'s Highcal";
|
|
break;
|
|
case MOD_PISTOL:
|
|
message = "almost survived an attack from";
|
|
message2 = "'s Machine Pistol - but didn't";
|
|
break;
|
|
case MOD_ASSAULT:
|
|
message = "gained a few new orifices courtesy of";
|
|
message2 = "'s Assault Rifle";
|
|
break;
|
|
|
|
default:
|
|
message = "was perforated by";
|
|
break;
|
|
}
|
|
|
|
if (message) {
|
|
CG_Printf( "%s %s %s%s\n",
|
|
targetName, message, attackerName, message2);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// we don't know what it was
|
|
CG_Printf( "%s died tragically.\n", targetName );
|
|
}
|
|
|
|
|
|
/*
|
|
==============
|
|
CG_EntityEvent
|
|
|
|
An entity has an event value
|
|
also called by CG_CheckPlayerstateEvents
|
|
==============
|
|
*/
|
|
#define DEBUGNAME(x) if(cg_debugEvents.integer){CG_Printf(x"\n");}
|
|
void CG_EntityEvent( centity_t *cent, vec3_t position ) {
|
|
entityState_t *es;
|
|
int event;
|
|
vec3_t dir;
|
|
const char *s;
|
|
int clientNum;
|
|
clientInfo_t *ci;
|
|
|
|
es = ¢->currentState;
|
|
event = es->event & ~EV_EVENT_BITS;
|
|
|
|
if ( cg_debugEvents.integer ) {
|
|
CG_Printf( "ent:%3i event:%3i ", es->number, event );
|
|
}
|
|
|
|
if ( !event ) {
|
|
DEBUGNAME("ZEROEVENT");
|
|
return;
|
|
}
|
|
|
|
clientNum = es->clientNum;
|
|
if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
|
|
clientNum = 0;
|
|
}
|
|
ci = &cgs.clientinfo[ clientNum ];
|
|
|
|
switch ( event ) {
|
|
//
|
|
// movement generated events
|
|
//
|
|
case EV_FOOTSTEP:
|
|
DEBUGNAME("EV_FOOTSTEP");
|
|
if (cg_footsteps.integer) {
|
|
trap_S_StartSound (NULL, es->number, CHAN_BODY,
|
|
cgs.media.footsteps[ ci->footsteps ][rand()&3] );
|
|
}
|
|
break;
|
|
case EV_FOOTSTEP_METAL:
|
|
DEBUGNAME("EV_FOOTSTEP_METAL");
|
|
if (cg_footsteps.integer) {
|
|
trap_S_StartSound (NULL, es->number, CHAN_BODY,
|
|
cgs.media.footsteps[ FOOTSTEP_METAL ][Q_rand()&3] );
|
|
}
|
|
break;
|
|
case EV_FOOTSPLASH:
|
|
DEBUGNAME("EV_FOOTSPLASH");
|
|
if (cg_footsteps.integer) {
|
|
trap_S_StartSound (NULL, es->number, CHAN_BODY,
|
|
cgs.media.footsteps[ FOOTSTEP_SPLASH ][Q_rand()&3] );
|
|
}
|
|
break;
|
|
case EV_FOOTWADE:
|
|
DEBUGNAME("EV_FOOTWADE");
|
|
if (cg_footsteps.integer) {
|
|
trap_S_StartSound (NULL, es->number, CHAN_BODY,
|
|
cgs.media.footsteps[ FOOTSTEP_SPLASH ][Q_rand()&3] );
|
|
}
|
|
break;
|
|
case EV_SWIM:
|
|
DEBUGNAME("EV_SWIM");
|
|
if (cg_footsteps.integer) {
|
|
trap_S_StartSound (NULL, es->number, CHAN_BODY,
|
|
cgs.media.footsteps[ FOOTSTEP_SPLASH ][Q_rand()&3] );
|
|
}
|
|
break;
|
|
|
|
|
|
case EV_FALL_SHORT:
|
|
DEBUGNAME("EV_FALL_SHORT");
|
|
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound );
|
|
if ( clientNum == cg.predictedPlayerState.clientNum ) {
|
|
// smooth landing z changes
|
|
cg.landChange = -8;
|
|
cg.landTime = cg.time;
|
|
}
|
|
break;
|
|
case EV_FALL_MEDIUM:
|
|
DEBUGNAME("EV_FALL_MEDIUM");
|
|
// use normal pain sound
|
|
trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100_1.ogg" ) );
|
|
if ( clientNum == cg.predictedPlayerState.clientNum ) {
|
|
// smooth landing z changes
|
|
cg.landChange = -16;
|
|
cg.landTime = cg.time;
|
|
}
|
|
break;
|
|
case EV_FALL_FAR:
|
|
DEBUGNAME("EV_FALL_FAR");
|
|
trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.ogg" ) );
|
|
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_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 ) {
|
|
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 || cg_synchronousClients.integer ) {
|
|
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_PAD:
|
|
DEBUGNAME("EV_JUMP_PAD");
|
|
// CG_Printf( "EV_JUMP_PAD w/effect #%i\n", es->eventParm );
|
|
{
|
|
localEntity_t *smoke;
|
|
vec3_t up = {0, 0, 1};
|
|
|
|
|
|
smoke = CG_SmokePuff( cent->lerpOrigin, up,
|
|
32,
|
|
1, 1, 1, 0.33f,
|
|
1000,
|
|
cg.time, 0,
|
|
LEF_PUFF_DONT_SCALE,
|
|
cgs.media.smokePuffShader );
|
|
}
|
|
|
|
// boing sound at origin, jump sound on player
|
|
trap_S_StartSound ( cent->lerpOrigin, -1, CHAN_VOICE, cgs.media.jumpPadSound );
|
|
trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.ogg" ) );
|
|
break;
|
|
//No longer being sent by the server.
|
|
/* case EV_JUMP:
|
|
DEBUGNAME("EV_JUMP");
|
|
trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.ogg" ) );
|
|
break;*/
|
|
case EV_TAUNT:
|
|
DEBUGNAME("EV_TAUNT");
|
|
trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.ogg" ) );
|
|
break;
|
|
case EV_TAUNT_YES:
|
|
DEBUGNAME("EV_TAUNT_YES");
|
|
CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_YES);
|
|
break;
|
|
case EV_TAUNT_NO:
|
|
DEBUGNAME("EV_TAUNT_NO");
|
|
CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_NO);
|
|
break;
|
|
case EV_TAUNT_FOLLOWME:
|
|
DEBUGNAME("EV_TAUNT_FOLLOWME");
|
|
CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_FOLLOWME);
|
|
break;
|
|
case EV_TAUNT_GETFLAG:
|
|
DEBUGNAME("EV_TAUNT_GETFLAG");
|
|
CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONGETFLAG);
|
|
break;
|
|
case EV_TAUNT_GUARDBASE:
|
|
DEBUGNAME("EV_TAUNT_GUARDBASE");
|
|
CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONDEFENSE);
|
|
break;
|
|
case EV_TAUNT_PATROL:
|
|
DEBUGNAME("EV_TAUNT_PATROL");
|
|
CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONPATROL);
|
|
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 );
|
|
break;
|
|
case EV_WATER_CLEAR:
|
|
DEBUGNAME("EV_WATER_CLEAR");
|
|
trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.ogg" ) );
|
|
break;
|
|
|
|
case EV_ITEM_PICKUP:
|
|
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 ( item->pickup_sound ) {
|
|
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 ) {
|
|
CG_ItemPickup( index );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EV_ITEM_STASH:
|
|
DEBUGNAME("EV_ITEM_STASH");
|
|
{
|
|
int commodity_id = es->eventParm & 0xFF;
|
|
int stash_qty = es->eventParm >> 8;
|
|
sfxHandle_t snd;
|
|
int txt;
|
|
|
|
char s[ MAX_SAY_TEXT ];
|
|
|
|
//events are global, and if it's not us picking up the stash, break out
|
|
if (es->number != cg.snap->ps.clientNum)
|
|
break;
|
|
|
|
if ( stash_qty == 0 ) {
|
|
snd = cgs.media.stash_full;
|
|
txt = cgs.media.CG_STASH_FULL;
|
|
} else {
|
|
snd = cgs.media.stash_pickup;
|
|
txt = cgs.media.CG_STASH_PICKUP;
|
|
}
|
|
|
|
trap_S_StartSound(NULL, es->number, CHAN_AUTO, snd );
|
|
trap_SQL_Run( s, sizeof(s), txt, commodity_id, stash_qty, 0 );
|
|
trap_Cmd_ExecuteText( EXEC_NOW, va("st_cp \"%s\" stash",s) );
|
|
}
|
|
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 ];
|
|
// powerup pickups are global
|
|
if( item->pickup_sound ) {
|
|
trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) );
|
|
}
|
|
|
|
// show icon and name on status bar
|
|
if ( es->number == cg.snap->ps.clientNum ) {
|
|
CG_ItemPickup( index );
|
|
}
|
|
}
|
|
break;
|
|
|
|
//
|
|
// weapon events
|
|
//
|
|
case EV_NOAMMO:
|
|
DEBUGNAME("EV_NOAMMO");
|
|
// trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.noAmmoSound );
|
|
if ( es->number == cg.snap->ps.clientNum ) {
|
|
CG_OutOfAmmoChange();
|
|
}
|
|
break;
|
|
case EV_CHANGE_WEAPON:
|
|
DEBUGNAME("EV_CHANGE_WEAPON");
|
|
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound );
|
|
break;
|
|
case EV_FIRE_WEAPON:
|
|
DEBUGNAME("EV_FIRE_WEAPON");
|
|
CG_FireWeapon( cent );
|
|
break;
|
|
case EV_FIRE_GRENADE:
|
|
DEBUGNAME("EV_FIRE_GRENADE");
|
|
cent->currentState.weapon = WP_GRENADE;
|
|
CG_FireWeapon( cent );
|
|
break;
|
|
case EV_FIRE_MELEE:
|
|
break;
|
|
case EV_RELOAD_WEAPON_FINISH:
|
|
case EV_RELOAD_WEAPON:
|
|
break;
|
|
case EV_USE_ITEM0:
|
|
DEBUGNAME("EV_USE_ITEM0");
|
|
CG_UseItem( cent );
|
|
break;
|
|
case EV_USE_ITEM1:
|
|
DEBUGNAME("EV_USE_ITEM1");
|
|
CG_UseItem( cent );
|
|
break;
|
|
case EV_USE_ITEM2:
|
|
DEBUGNAME("EV_USE_ITEM2");
|
|
CG_UseItem( cent );
|
|
break;
|
|
case EV_USE_ITEM3:
|
|
DEBUGNAME("EV_USE_ITEM3");
|
|
CG_UseItem( cent );
|
|
break;
|
|
case EV_USE_ITEM4:
|
|
DEBUGNAME("EV_USE_ITEM4");
|
|
CG_UseItem( cent );
|
|
break;
|
|
case EV_USE_ITEM5:
|
|
DEBUGNAME("EV_USE_ITEM5");
|
|
CG_UseItem( cent );
|
|
break;
|
|
case EV_USE_ITEM6:
|
|
DEBUGNAME("EV_USE_ITEM6");
|
|
CG_UseItem( cent );
|
|
break;
|
|
case EV_USE_ITEM7:
|
|
DEBUGNAME("EV_USE_ITEM7");
|
|
CG_UseItem( cent );
|
|
break;
|
|
case EV_USE_ITEM8:
|
|
DEBUGNAME("EV_USE_ITEM8");
|
|
CG_UseItem( cent );
|
|
break;
|
|
case EV_USE_ITEM9:
|
|
DEBUGNAME("EV_USE_ITEM9");
|
|
CG_UseItem( cent );
|
|
break;
|
|
case EV_USE_ITEM10:
|
|
DEBUGNAME("EV_USE_ITEM10");
|
|
CG_UseItem( cent );
|
|
break;
|
|
case EV_USE_ITEM11:
|
|
DEBUGNAME("EV_USE_ITEM11");
|
|
CG_UseItem( cent );
|
|
break;
|
|
case EV_USE_ITEM12:
|
|
DEBUGNAME("EV_USE_ITEM12");
|
|
CG_UseItem( cent );
|
|
break;
|
|
case EV_USE_ITEM13:
|
|
DEBUGNAME("EV_USE_ITEM13");
|
|
CG_UseItem( cent );
|
|
break;
|
|
case EV_USE_ITEM14:
|
|
DEBUGNAME("EV_USE_ITEM14");
|
|
CG_UseItem( cent );
|
|
break;
|
|
|
|
//=================================================================
|
|
|
|
//
|
|
// other events
|
|
//
|
|
case EV_PLAYER_TELEPORT_IN:
|
|
DEBUGNAME("EV_PLAYER_TELEPORT_IN");
|
|
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleInSound );
|
|
CG_SpawnEffect( position);
|
|
break;
|
|
|
|
case EV_PLAYER_TELEPORT_OUT:
|
|
DEBUGNAME("EV_PLAYER_TELEPORT_OUT");
|
|
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleOutSound );
|
|
CG_SpawnEffect( position);
|
|
break;
|
|
|
|
case EV_ITEM_POP:
|
|
DEBUGNAME("EV_ITEM_POP");
|
|
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );
|
|
break;
|
|
case EV_ITEM_RESPAWN:
|
|
DEBUGNAME("EV_ITEM_RESPAWN");
|
|
cent->miscTime = cg.time; // scale up from this
|
|
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );
|
|
break;
|
|
|
|
case EV_GRENADE_BOUNCE:
|
|
DEBUGNAME("EV_GRENADE_BOUNCE");
|
|
if ( Q_rand() & 1 ) {
|
|
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb1aSound );
|
|
} else {
|
|
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb2aSound );
|
|
}
|
|
break;
|
|
|
|
|
|
case EV_C4_STICK:
|
|
DEBUGNAME("EV_C4_STICK");
|
|
if( es->eventParm & SURF_FLESH ) {
|
|
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimplSound );
|
|
} else if( es->eventParm & SURF_METALSTEPS ) {
|
|
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpmSound );
|
|
} else {
|
|
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpdSound );
|
|
}
|
|
break;
|
|
|
|
case EV_C4_TRIGGER:
|
|
DEBUGNAME("EV_C4_TRIGGER");
|
|
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbactvSound );
|
|
break;
|
|
case EV_SCOREPLUM:
|
|
DEBUGNAME("EV_SCOREPLUM");
|
|
CG_ScorePlum( cent->currentState.otherEntityNum, cent->lerpOrigin, cent->currentState.time );
|
|
break;
|
|
|
|
//
|
|
// missile impacts
|
|
//
|
|
case EV_MISSILE_HIT:
|
|
DEBUGNAME("EV_MISSILE_HIT");
|
|
ByteToDir( es->eventParm, dir );
|
|
CG_MissileHitPlayer( es->weapon, position, dir, es->otherEntityNum );
|
|
break;
|
|
|
|
case EV_MISSILE_MISS:
|
|
DEBUGNAME("EV_MISSILE_MISS");
|
|
ByteToDir( es->eventParm, dir );
|
|
CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_DEFAULT );
|
|
break;
|
|
|
|
case EV_MISSILE_MISS_METAL:
|
|
DEBUGNAME("EV_MISSILE_MISS_METAL");
|
|
ByteToDir( es->eventParm, dir );
|
|
CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_METAL );
|
|
break;
|
|
|
|
case EV_BULLET_HIT_WALL:
|
|
DEBUGNAME("EV_BULLET_HIT_WALL");
|
|
ByteToDir( es->eventParm, dir );
|
|
CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD );
|
|
break;
|
|
|
|
case EV_BULLET_HIT_FLESH:
|
|
DEBUGNAME("EV_BULLET_HIT_FLESH");
|
|
CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm );
|
|
break;
|
|
|
|
case EV_SHOTGUN:
|
|
DEBUGNAME("EV_SHOTGUN");
|
|
CG_ShotgunFire( es );
|
|
break;
|
|
|
|
case EV_GENERAL_SOUND:
|
|
DEBUGNAME("EV_GENERAL_SOUND");
|
|
if ( cgs.gameSounds[ es->eventParm ] ) {
|
|
trap_S_StartSound (NULL, es->number, CHAN_VOICE, cgs.gameSounds[ es->eventParm ] );
|
|
} else {
|
|
s = CG_ConfigString( CS_SOUNDS + es->eventParm );
|
|
trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, s ) );
|
|
}
|
|
break;
|
|
|
|
case EV_GLOBAL_SOUND: // play from the player's head so it never diminishes
|
|
DEBUGNAME("EV_GLOBAL_SOUND");
|
|
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 ) );
|
|
}
|
|
break;
|
|
|
|
case EV_GLOBAL_TEAM_SOUND: // play from the player's head so it never diminishes
|
|
{
|
|
DEBUGNAME("EV_GLOBAL_TEAM_SOUND");
|
|
switch( es->eventParm ) {
|
|
case GTS_RED_CAPTURE: // CTF: red team captured the blue flag, 1FCTF: red team captured the neutral flag
|
|
break;
|
|
case GTS_BLUE_CAPTURE: // CTF: blue team captured the red flag, 1FCTF: blue team captured the neutral flag
|
|
break;
|
|
case GTS_RED_RETURN: // CTF: blue flag returned, 1FCTF: never used
|
|
break;
|
|
case GTS_BLUE_RETURN: // CTF red flag returned, 1FCTF: neutral flag returned
|
|
break;
|
|
|
|
case GTS_RED_TAKEN: // CTF: red team took blue flag, 1FCTF: blue team took the neutral flag
|
|
break;
|
|
case GTS_BLUE_TAKEN: // CTF: blue team took the red flag, 1FCTF red team took the neutral flag
|
|
break;
|
|
case GTS_REDTEAM_SCORED:
|
|
break;
|
|
case GTS_BLUETEAM_SCORED:
|
|
break;
|
|
case GTS_REDTEAM_TOOK_LEAD:
|
|
break;
|
|
case GTS_BLUETEAM_TOOK_LEAD:
|
|
break;
|
|
case GTS_TEAMS_ARE_TIED:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case EV_PAIN:
|
|
// local player sounds are triggered in CG_CheckLocalSounds,
|
|
// so ignore events on the player
|
|
DEBUGNAME("EV_PAIN");
|
|
if ( cent->currentState.number != cg.snap->ps.clientNum ) {
|
|
CG_PainEvent( cent, es->eventParm );
|
|
}
|
|
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.ogg", event - EV_DEATH1 + 1) ) );
|
|
break;
|
|
|
|
case EV_OBITUARY:
|
|
DEBUGNAME("EV_OBITUARY");
|
|
if ( cgs.gametype == GT_FFA ) {
|
|
CG_Obituary( es );
|
|
}
|
|
break;
|
|
|
|
case EV_GIB_PLAYER:
|
|
DEBUGNAME("EV_GIB_PLAYER");
|
|
CG_GibPlayer( cent->lerpOrigin );
|
|
break;
|
|
|
|
case EV_STOPLOOPINGSOUND:
|
|
DEBUGNAME("EV_STOPLOOPINGSOUND");
|
|
trap_S_StopLoopingSound( es->number );
|
|
es->loopSound = 0;
|
|
break;
|
|
|
|
default:
|
|
DEBUGNAME("UNKNOWN");
|
|
CG_Error( "Unknown event: %i", event );
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
==============
|
|
CG_CheckEvents
|
|
|
|
==============
|
|
*/
|
|
void CG_CheckEvents( centity_t *cent ) {
|
|
// check for event-only entities
|
|
if ( cent->currentState.eType > ET_EVENTS ) {
|
|
if ( cent->previousEvent ) {
|
|
return; // already fired
|
|
}
|
|
// if this is a player event set the entity number of the client entity number
|
|
if ( cent->currentState.eFlags & EF_PLAYER_EVENT ) {
|
|
cent->currentState.number = cent->currentState.otherEntityNum;
|
|
}
|
|
|
|
cent->previousEvent = 1;
|
|
|
|
cent->currentState.event = cent->currentState.eType - ET_EVENTS;
|
|
} else {
|
|
// check for events riding with another entity
|
|
if ( cent->currentState.event == cent->previousEvent ) {
|
|
return;
|
|
}
|
|
cent->previousEvent = cent->currentState.event;
|
|
if ( ( cent->currentState.event & ~EV_EVENT_BITS ) == 0 ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// calculate the position at exactly the frame time
|
|
BG_EvaluateTrajectory( ¢->currentState.pos, cg.snap->serverTime, cent->lerpOrigin );
|
|
CG_SetEntitySoundPosition( cent );
|
|
|
|
CG_EntityEvent( cent, cent->lerpOrigin );
|
|
}
|
|
|