2
===========================================================================
3
Copyright (C) 1999-2005 Id Software, Inc.
5
This file is part of Quake III Arena source code.
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.
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.
17
You should have received a copy of the GNU General Public License
18
along with Quake III Arena source code; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
===========================================================================
23
// cg_event.c -- handle entity events at snapshot or playerstate transitions
27
// for the voice chats
28
#ifdef MISSIONPACK // bk001205
29
#include "../../ui/menudef.h"
31
//==========================================================================
37
Also called by scoreboard drawing
40
const char *CG_PlaceString( int rank ) {
44
if ( rank & RANK_TIED_FLAG ) {
45
rank &= ~RANK_TIED_FLAG;
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 ) {
59
} else if ( rank == 12 ) {
61
} else if ( rank == 13 ) {
63
} else if ( rank % 10 == 1 ) {
65
} else if ( rank % 10 == 2 ) {
67
} else if ( rank % 10 == 3 ) {
73
Com_sprintf( str, sizeof( str ), "%s%s", t, s );
82
static void CG_Obituary( entityState_t *ent ) {
87
const char *targetInfo;
88
const char *attackerInfo;
90
char attackerName[32];
94
target = ent->otherEntityNum;
95
attacker = ent->otherEntityNum2;
98
if ( target < 0 || target >= MAX_CLIENTS ) {
99
CG_Error( "CG_Obituary: target out of range" );
101
ci = &cgs.clientinfo[target];
103
if ( attacker < 0 || attacker >= MAX_CLIENTS ) {
104
attacker = ENTITYNUM_WORLD;
107
attackerInfo = CG_ConfigString( CS_PLAYERS + attacker );
110
targetInfo = CG_ConfigString( CS_PLAYERS + target );
114
Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof(targetName) - 2);
115
strcat( targetName, S_COLOR_WHITE );
119
// check for single client messages
123
message = "suicides";
126
message = "cratered";
129
message = "was squished";
132
message = "sank like a rock";
138
message = "does a back flip into the lava";
140
case MOD_TARGET_LASER:
141
message = "saw the light";
143
case MOD_TRIGGER_HURT:
144
message = "was in the wrong place";
151
if (attacker == target) {
156
message = "goes out with a bang";
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";
165
message = "tripped on his own grenade";
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";
173
message = "blew himself up";
175
case MOD_PLASMA_SPLASH:
176
if ( gender == GENDER_FEMALE )
177
message = "melted herself";
178
else if ( gender == GENDER_NEUTER )
179
message = "melted itself";
181
message = "melted himself";
184
message = "should have used a smaller gun";
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";
193
message = "found his prox mine";
198
if ( gender == GENDER_FEMALE )
199
message = "killed herself";
200
else if ( gender == GENDER_NEUTER )
201
message = "killed itself";
203
message = "killed himself";
209
CG_Printf( "%s %s.\n", targetName, message);
213
// check for kill messages from the current clientNum
214
if ( attacker == cg.snap->ps.clientNum ) {
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] );
222
s = va("You fragged %s", targetName );
225
if (!(cg_singlePlayerActive.integer && cg_cameraOrbit.integer)) {
226
CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
229
CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
232
// print the text message as well
235
// check for double client messages
236
if ( !attackerInfo ) {
237
attacker = ENTITYNUM_WORLD;
238
strcpy( attackerName, "noname" );
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 ) );
248
if ( attacker != ENTITYNUM_WORLD ) {
251
message = "was caught by";
254
message = "was pummeled by";
257
message = "was machinegunned by";
260
message = "was gunned down by";
264
message2 = "'s grenade";
266
case MOD_GRENADE_SPLASH:
267
message = "was shredded by";
268
message2 = "'s shrapnel";
272
message2 = "'s rocket";
274
case MOD_ROCKET_SPLASH:
275
message = "almost dodged";
276
message2 = "'s rocket";
279
message = "was melted by";
280
message2 = "'s plasmagun";
282
case MOD_PLASMA_SPLASH:
283
message = "was melted by";
284
message2 = "'s plasmagun";
287
message = "was railed by";
290
message = "was electrocuted by";
294
message = "was blasted by";
299
message = "was nailed by";
302
message = "got lead poisoning from";
303
message2 = "'s Chaingun";
305
case MOD_PROXIMITY_MINE:
306
message = "was too close to";
307
message2 = "'s Prox Mine";
310
message = "falls to";
311
message2 = "'s Kamikaze blast";
314
message = "was juiced by";
318
message = "tried to invade";
319
message2 = "'s personal space";
322
message = "was killed by";
327
CG_Printf( "%s %s %s%s\n",
328
targetName, message, attackerName, message2);
333
// we don't know what it was
334
CG_Printf( "%s died.\n", targetName );
337
//==========================================================================
344
static void CG_UseItem( centity_t *cent ) {
346
int itemNum, clientNum;
350
es = ¢->currentState;
352
itemNum = (es->event & ~EV_EVENT_BITS) - EV_USE_ITEM0;
353
if ( itemNum < 0 || itemNum > HI_NUM_HOLDABLE ) {
357
// print a message if the local player
358
if ( es->number == cg.snap->ps.clientNum ) {
360
CG_CenterPrint( "No item to use", SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
362
item = BG_FindItemForHoldable( itemNum );
363
CG_CenterPrint( va("Use %s", item->pickup_name), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
370
trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useNothingSound );
377
clientNum = cent->currentState.clientNum;
378
if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
379
ci = &cgs.clientinfo[ clientNum ];
380
ci->medkitUsageTime = cg.time;
382
trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.medkitSound );
391
case HI_INVULNERABILITY:
392
trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useInvulnerabilitySound );
403
A new item was picked up this frame
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;
426
Also called by playerstate transition
429
void CG_PainEvent( centity_t *cent, int health ) {
432
// don't do more than two pain sounds a second
433
if ( cg.time - cent->pe.painTime < 500 ) {
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";
444
snd = "*pain100_1.wav";
446
trap_S_StartSound( NULL, cent->currentState.number, CHAN_VOICE,
447
CG_CustomSound( cent->currentState.number, snd ) );
449
// save pain time for programitic twitch animation
450
cent->pe.painTime = cg.time;
451
cent->pe.painDirection ^= 1;
460
An entity has an event value
461
also called by CG_CheckPlayerstateEvents
464
#define DEBUGNAME(x) if(cg_debugEvents.integer){CG_Printf(x"\n");}
465
void CG_EntityEvent( centity_t *cent, vec3_t position ) {
473
es = ¢->currentState;
474
event = es->event & ~EV_EVENT_BITS;
476
if ( cg_debugEvents.integer ) {
477
CG_Printf( "ent:%3i event:%3i ", es->number, event );
481
DEBUGNAME("ZEROEVENT");
485
clientNum = es->clientNum;
486
if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
489
ci = &cgs.clientinfo[ clientNum ];
493
// movement generated events
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] );
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] );
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] );
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] );
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] );
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
538
cg.landTime = cg.time;
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
548
cg.landTime = cg.time;
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
558
cg.landTime = cg.time;
565
case EV_STEP_16: // smooth out step up transitions
566
DEBUGNAME("EV_STEP");
572
if ( clientNum != cg.predictedPlayerState.clientNum ) {
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 ) {
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;
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;
594
cg.stepTime = cg.time;
599
DEBUGNAME("EV_JUMP_PAD");
600
// CG_Printf( "EV_JUMP_PAD w/effect #%i\n", es->eventParm );
602
localEntity_t *smoke;
603
vec3_t up = {0, 0, 1};
606
smoke = CG_SmokePuff( cent->lerpOrigin, up,
612
cgs.media.smokePuffShader );
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" ) );
621
DEBUGNAME("EV_JUMP");
622
trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) );
625
DEBUGNAME("EV_TAUNT");
626
trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.wav" ) );
630
DEBUGNAME("EV_TAUNT_YES");
631
CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_YES);
634
DEBUGNAME("EV_TAUNT_NO");
635
CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_NO);
637
case EV_TAUNT_FOLLOWME:
638
DEBUGNAME("EV_TAUNT_FOLLOWME");
639
CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_FOLLOWME);
641
case EV_TAUNT_GETFLAG:
642
DEBUGNAME("EV_TAUNT_GETFLAG");
643
CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONGETFLAG);
645
case EV_TAUNT_GUARDBASE:
646
DEBUGNAME("EV_TAUNT_GUARDBASE");
647
CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONDEFENSE);
649
case EV_TAUNT_PATROL:
650
DEBUGNAME("EV_TAUNT_PATROL");
651
CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONPATROL);
655
DEBUGNAME("EV_WATER_TOUCH");
656
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrInSound );
659
DEBUGNAME("EV_WATER_LEAVE");
660
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound );
663
DEBUGNAME("EV_WATER_UNDER");
664
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound );
667
DEBUGNAME("EV_WATER_CLEAR");
668
trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.wav" ) );
672
DEBUGNAME("EV_ITEM_PICKUP");
677
index = es->eventParm; // player predicted
679
if ( index < 1 || index >= bg_numItems ) {
682
item = &bg_itemlist[ index ];
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) {
690
switch (item->giTag ) {
692
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.scoutSound );
695
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.guardSound );
698
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.doublerSound );
701
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.ammoregenSound );
706
trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) );
709
// show icon and name on status bar
710
if ( es->number == cg.snap->ps.clientNum ) {
711
CG_ItemPickup( index );
716
case EV_GLOBAL_ITEM_PICKUP:
717
DEBUGNAME("EV_GLOBAL_ITEM_PICKUP");
722
index = es->eventParm; // player predicted
724
if ( index < 1 || index >= bg_numItems ) {
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 ) );
733
// show icon and name on status bar
734
if ( es->number == cg.snap->ps.clientNum ) {
735
CG_ItemPickup( index );
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();
750
case EV_CHANGE_WEAPON:
751
DEBUGNAME("EV_CHANGE_WEAPON");
752
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound );
755
DEBUGNAME("EV_FIRE_WEAPON");
756
CG_FireWeapon( cent );
760
DEBUGNAME("EV_USE_ITEM0");
764
DEBUGNAME("EV_USE_ITEM1");
768
DEBUGNAME("EV_USE_ITEM2");
772
DEBUGNAME("EV_USE_ITEM3");
776
DEBUGNAME("EV_USE_ITEM4");
780
DEBUGNAME("EV_USE_ITEM5");
784
DEBUGNAME("EV_USE_ITEM6");
788
DEBUGNAME("EV_USE_ITEM7");
792
DEBUGNAME("EV_USE_ITEM8");
796
DEBUGNAME("EV_USE_ITEM9");
800
DEBUGNAME("EV_USE_ITEM10");
804
DEBUGNAME("EV_USE_ITEM11");
808
DEBUGNAME("EV_USE_ITEM12");
812
DEBUGNAME("EV_USE_ITEM13");
816
DEBUGNAME("EV_USE_ITEM14");
820
//=================================================================
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);
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);
838
DEBUGNAME("EV_ITEM_POP");
839
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound );
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 );
847
case EV_GRENADE_BOUNCE:
848
DEBUGNAME("EV_GRENADE_BOUNCE");
850
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb1aSound );
852
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb2aSound );
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 );
864
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpdSound );
868
case EV_PROXIMITY_MINE_TRIGGER:
869
DEBUGNAME("EV_PROXIMITY_MINE_TRIGGER");
870
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbactvSound );
873
DEBUGNAME("EV_KAMIKAZE");
874
CG_KamikazeEffect( cent->lerpOrigin );
876
case EV_OBELISKEXPLODE:
877
DEBUGNAME("EV_OBELISKEXPLODE");
878
CG_ObeliskExplode( cent->lerpOrigin, es->eventParm );
881
DEBUGNAME("EV_OBELISKPAIN");
882
CG_ObeliskPain( cent->lerpOrigin );
884
case EV_INVUL_IMPACT:
885
DEBUGNAME("EV_INVUL_IMPACT");
886
CG_InvulnerabilityImpact( cent->lerpOrigin, cent->currentState.angles );
889
DEBUGNAME("EV_JUICED");
890
CG_InvulnerabilityJuiced( cent->lerpOrigin );
892
case EV_LIGHTNINGBOLT:
893
DEBUGNAME("EV_LIGHTNINGBOLT");
894
CG_LightningBoltBeam(es->origin2, es->pos.trBase);
898
DEBUGNAME("EV_SCOREPLUM");
899
CG_ScorePlum( cent->currentState.otherEntityNum, cent->lerpOrigin, cent->currentState.time );
906
DEBUGNAME("EV_MISSILE_HIT");
907
ByteToDir( es->eventParm, dir );
908
CG_MissileHitPlayer( es->weapon, position, dir, es->otherEntityNum );
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 );
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 );
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 );
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 );
940
case EV_BULLET_HIT_FLESH:
941
DEBUGNAME("EV_BULLET_HIT_FLESH");
942
CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm );
946
DEBUGNAME("EV_SHOTGUN");
947
CG_ShotgunFire( es );
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 ] );
955
s = CG_ConfigString( CS_SOUNDS + es->eventParm );
956
trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, s ) );
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 ] );
965
s = CG_ConfigString( CS_SOUNDS + es->eventParm );
966
trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, CG_CustomSound( es->number, s ) );
970
case EV_GLOBAL_TEAM_SOUND: // play from the player's head so it never diminishes
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 );
978
CG_AddBufferedSound( cgs.media.captureOpponentSound );
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 );
984
CG_AddBufferedSound( cgs.media.captureOpponentSound );
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 );
990
CG_AddBufferedSound( cgs.media.returnOpponentSound );
992
CG_AddBufferedSound( cgs.media.blueFlagReturnedSound );
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 );
998
CG_AddBufferedSound( cgs.media.returnOpponentSound );
1000
CG_AddBufferedSound( cgs.media.redFlagReturnedSound );
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]) {
1008
if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
1010
if (cgs.gametype == GT_1FCTF)
1011
CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound );
1014
CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound );
1016
else if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
1018
if (cgs.gametype == GT_1FCTF)
1019
CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound );
1022
CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound );
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]) {
1031
if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) {
1033
if (cgs.gametype == GT_1FCTF)
1034
CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound );
1037
CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound );
1039
else if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) {
1041
if (cgs.gametype == GT_1FCTF)
1042
CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound );
1045
CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound );
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 );
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 );
1060
case GTS_REDTEAM_SCORED:
1061
CG_AddBufferedSound(cgs.media.redScoredSound);
1063
case GTS_BLUETEAM_SCORED:
1064
CG_AddBufferedSound(cgs.media.blueScoredSound);
1066
case GTS_REDTEAM_TOOK_LEAD:
1067
CG_AddBufferedSound(cgs.media.redLeadsSound);
1069
case GTS_BLUETEAM_TOOK_LEAD:
1070
CG_AddBufferedSound(cgs.media.blueLeadsSound);
1072
case GTS_TEAMS_ARE_TIED:
1073
CG_AddBufferedSound( cgs.media.teamsTiedSound );
1077
trap_S_StartLocalSound(cgs.media.kamikazeFarSound, CHAN_ANNOUNCER);
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 );
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) ) );
1105
DEBUGNAME("EV_OBITUARY");
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;
1118
trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.quadSound );
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;
1126
trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.protectSound );
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;
1134
trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.regenSound );
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 );
1145
CG_GibPlayer( cent->lerpOrigin );
1148
case EV_STOPLOOPINGSOUND:
1149
DEBUGNAME("EV_STOPLOOPINGSOUND");
1150
trap_S_StopLoopingSound( es->number );
1155
DEBUGNAME("EV_DEBUG_LINE");
1160
DEBUGNAME("UNKNOWN");
1161
CG_Error( "Unknown event: %i", event );
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
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;
1185
cent->previousEvent = 1;
1187
cent->currentState.event = cent->currentState.eType - ET_EVENTS;
1189
// check for events riding with another entity
1190
if ( cent->currentState.event == cent->previousEvent ) {
1193
cent->previousEvent = cent->currentState.event;
1194
if ( ( cent->currentState.event & ~EV_EVENT_BITS ) == 0 ) {
1199
// calculate the position at exactly the frame time
1200
BG_EvaluateTrajectory( ¢->currentState.pos, cg.snap->serverTime, cent->lerpOrigin );
1201
CG_SetEntitySoundPosition( cent );
1203
CG_EntityEvent( cent, cent->lerpOrigin );