void CG_EntityEvent( centity_t *cent, vec3_t position ) { entityState_t *es; int event; vec3_t dir; const char *s; int playerNum; playerInfo_t *pi; int i; 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; } playerNum = es->playerNum; if ( playerNum < 0 || playerNum >= MAX_CLIENTS ) { playerNum = 0; } pi = &cgs.playerinfo[ playerNum ]; 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[ pi->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 ][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 ][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 ][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 ][rand()&3] ); } break; case EV_FALL_SHORT: DEBUGNAME("EV_FALL_SHORT"); trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound ); for (i = 0; i < CG_MaxSplitView(); i++) { if ( playerNum == cg.snap->pss[i].playerNum ) { // smooth landing z changes cg.localPlayers[i].landChange = -8; cg.localPlayers[i].landTime = cg.time; } } break; case EV_FALL_MEDIUM: DEBUGNAME("EV_FALL_MEDIUM"); // use normal pain sound if (cgs.fallDamage) { trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100_1.wav" ) ); } else { trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound ); } for (i = 0; i < CG_MaxSplitView(); i++) { if ( playerNum == cg.snap->pss[i].playerNum ) { // smooth landing z changes cg.localPlayers[i].landChange = -16; cg.localPlayers[i].landTime = cg.time; } } break; case EV_FALL_FAR: DEBUGNAME("EV_FALL_FAR"); if (cgs.fallDamage) { trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) ); } else { trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound ); } cent->pe.painTime = cg.time; // don't play a pain sound right after this for (i = 0; i < CG_MaxSplitView(); i++) { if ( playerNum == cg.snap->pss[i].playerNum ) { // smooth landing z changes cg.localPlayers[i].landChange = -24; cg.localPlayers[i].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; localPlayer_t *player; playerState_t *ps; for (i = 0; i < CG_MaxSplitView(); i++) { player = &cg.localPlayers[i]; ps = &cg.snap->pss[i]; if ( playerNum != ps->playerNum ) { continue; } // if we are interpolating, we don't need to smooth steps if ( cg.demoPlayback || (ps->pm_flags & PMF_FOLLOW) || cg_nopredict.integer || cg_synchronousClients.integer ) { continue; } // check for stepping up before a previous step is completed delta = cg.time - player->stepTime; if (delta < STEP_TIME) { oldStep = player->stepChange * (STEP_TIME - delta) / STEP_TIME; } else { oldStep = 0; } // add this amount step = 4 * (event - EV_STEP_4 + 1 ); player->stepChange = oldStep + step; if ( player->stepChange > MAX_STEP_CHANGE ) { player->stepChange = MAX_STEP_CHANGE; } player->stepTime = cg.time; } break; } case EV_JUMP_PAD: DEBUGNAME("EV_JUMP_PAD"); // CG_Printf( "EV_JUMP_PAD w/effect #%i\n", es->eventParm ); { vec3_t up = {0, 0, 1}; 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.wav" ) ); 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; #ifdef MISSIONPACK case EV_TAUNT_YES: DEBUGNAME("EV_TAUNT_YES"); CG_VoiceChatLocal(~0, SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_YES); break; case EV_TAUNT_NO: DEBUGNAME("EV_TAUNT_NO"); CG_VoiceChatLocal(~0, SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_NO); break; case EV_TAUNT_FOLLOWME: DEBUGNAME("EV_TAUNT_FOLLOWME"); CG_VoiceChatLocal(~0, SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_FOLLOWME); break; case EV_TAUNT_GETFLAG: DEBUGNAME("EV_TAUNT_GETFLAG"); CG_VoiceChatLocal(~0, SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONGETFLAG); break; case EV_TAUNT_GUARDBASE: DEBUGNAME("EV_TAUNT_GUARDBASE"); CG_VoiceChatLocal(~0, SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONDEFENSE); break; case EV_TAUNT_PATROL: DEBUGNAME("EV_TAUNT_PATROL"); CG_VoiceChatLocal(~0, SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONPATROL); break; #endif 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.wav" ) ); 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_ItemForItemNum( index ); // powerups and team items will have a separate global sound, this one // will be played at prediction time if ( item->giType == IT_POWERUP || item->giType == IT_TEAM) { trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.n_healthSound ); } else if (item->giType == IT_PERSISTANT_POWERUP) { #ifdef MISSIONPACK switch (item->giTag ) { case PW_SCOUT: trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.scoutSound ); break; case PW_GUARD: trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.guardSound ); break; case PW_DOUBLER: trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.doublerSound ); break; case PW_AMMOREGEN: trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.ammoregenSound ); break; } #endif } else { trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.itemPickupSounds[ index ] ); } // show icon and name on status bar for (i = 0; i < CG_MaxSplitView(); i++) { if ( es->number == cg.snap->pss[i].playerNum ) { CG_ItemPickup( i, index ); } } } break; case EV_GLOBAL_ITEM_PICKUP: DEBUGNAME("EV_GLOBAL_ITEM_PICKUP"); { int index; index = es->eventParm; // player predicted if ( index < 1 || index >= BG_NumItems() ) { break; } // powerup pickups are global trap_S_StartLocalSound( cgs.media.itemPickupSounds[ index ], CHAN_AUTO ); // show icon and name on status bar for (i = 0; i < CG_MaxSplitView(); i++) { if ( es->number == cg.snap->pss[i].playerNum ) { CG_ItemPickup( i, index ); } } } break; // // weapon events // case EV_NOAMMO: DEBUGNAME("EV_NOAMMO"); // trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.noAmmoSound ); for (i = 0; i < CG_MaxSplitView(); i++) { if ( es->number == cg.snap->pss[i].playerNum ) { CG_OutOfAmmoChange(i); } } 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_USE_ITEM0: case EV_USE_ITEM1: case EV_USE_ITEM2: case EV_USE_ITEM3: case EV_USE_ITEM4: case EV_USE_ITEM5: case EV_USE_ITEM6: case EV_USE_ITEM7: case EV_USE_ITEM8: case EV_USE_ITEM9: case EV_USE_ITEM10: case EV_USE_ITEM11: case EV_USE_ITEM12: case EV_USE_ITEM13: case EV_USE_ITEM14: case EV_USE_ITEM15: DEBUGNAME2("EV_USE_ITEM%d", event - EV_USE_ITEM0); 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 ( 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; #ifdef MISSIONPACK case EV_PROXIMITY_MINE_STICK: DEBUGNAME("EV_PROXIMITY_MINE_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_PROXIMITY_MINE_TRIGGER: DEBUGNAME("EV_PROXIMITY_MINE_TRIGGER"); trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbactvSound ); break; case EV_KAMIKAZE: DEBUGNAME("EV_KAMIKAZE"); CG_KamikazeEffect( cent->lerpOrigin ); break; case EV_OBELISKEXPLODE: DEBUGNAME("EV_OBELISKEXPLODE"); CG_ObeliskExplode( cent->lerpOrigin, es->eventParm ); break; case EV_OBELISKPAIN: DEBUGNAME("EV_OBELISKPAIN"); CG_ObeliskPain( cent->lerpOrigin ); break; case EV_INVUL_IMPACT: DEBUGNAME("EV_INVUL_IMPACT"); CG_InvulnerabilityImpact( cent->lerpOrigin, cent->currentState.angles ); break; case EV_JUICED: DEBUGNAME("EV_JUICED"); CG_InvulnerabilityJuiced( cent->lerpOrigin ); break; case EV_LIGHTNINGBOLT: DEBUGNAME("EV_LIGHTNINGBOLT"); CG_LightningBoltBeam(es->origin2, es->pos.trBase); break; #endif 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_RAILTRAIL: DEBUGNAME("EV_RAILTRAIL"); cent->currentState.weapon = WP_RAILGUN; if ( es->playerNum >= 0 && es->playerNum < MAX_CLIENTS ) { for (i = 0; i < CG_MaxSplitView(); i++) { if ( es->playerNum == cg.snap->pss[i].playerNum && !cg.localPlayers[i].renderingThirdPerson) { if(cg_drawGun[i].integer == 2) VectorMA(es->origin2, 8, cg.refdef.viewaxis[1], es->origin2); else if(cg_drawGun[i].integer == 3) VectorMA(es->origin2, 4, cg.refdef.viewaxis[1], es->origin2); break; } } } CG_RailTrail(pi, es->origin2, es->pos.trBase); // if the end was on a nomark surface, don't make an explosion if ( es->eventParm != 255 ) { ByteToDir( es->eventParm, dir ); CG_MissileHitWall( es->weapon, es->playerNum, position, dir, IMPACTSOUND_DEFAULT ); } 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 as a local sound so it never diminishes DEBUGNAME("EV_GLOBAL_SOUND"); if ( cgs.gameSounds[ es->eventParm ] ) { trap_S_StartLocalSound( cgs.gameSounds[ es->eventParm ], CHAN_AUTO ); } else { s = CG_ConfigString( CS_SOUNDS + es->eventParm ); trap_S_StartLocalSound( CG_CustomSound( es->number, s ), CHAN_AUTO ); } break; case EV_GLOBAL_TEAM_SOUND: // play as a local sound so it never diminishes DEBUGNAME("EV_GLOBAL_TEAM_SOUND"); { qboolean blueTeam = qfalse; qboolean redTeam = qfalse; qboolean localHasBlue = qfalse; qboolean localHasRed = qfalse; qboolean localHasNeutral = qfalse; // Check if any local player is on blue/red team or has flags. for (i = 0; i < CG_MaxSplitView(); i++) { if (cg.snap->playerNums[i] == -1) { continue; } if (cg.snap->pss[i].persistant[PERS_TEAM] == TEAM_BLUE) { blueTeam = qtrue; } if (cg.snap->pss[i].persistant[PERS_TEAM] == TEAM_RED) { redTeam = qtrue; } if (cg.snap->pss[i].powerups[PW_BLUEFLAG]) { localHasBlue = qtrue; } if (cg.snap->pss[i].powerups[PW_REDFLAG]) { localHasRed = qtrue; } if (cg.snap->pss[i].powerups[PW_NEUTRALFLAG]) { localHasNeutral = qtrue; } } // ZTM: NOTE: Some of these sounds don't really work with local player on different teams. // New games might want to replace you/enemy sounds with red/blue. // See http://github.com/zturtleman/spearmint/wiki/New-Sounds switch( es->eventParm ) { case GTS_RED_CAPTURE: // CTF: red team captured the blue flag, 1FCTF: red team captured the neutral flag if ( redTeam ) CG_AddBufferedSound( cgs.media.captureYourTeamSound ); else CG_AddBufferedSound( cgs.media.captureOpponentSound ); break; case GTS_BLUE_CAPTURE: // CTF: blue team captured the red flag, 1FCTF: blue team captured the neutral flag if ( blueTeam ) CG_AddBufferedSound( cgs.media.captureYourTeamSound ); else CG_AddBufferedSound( cgs.media.captureOpponentSound ); break; case GTS_RED_RETURN: // CTF: blue flag returned, 1FCTF: never used if ( redTeam ) CG_AddBufferedSound( cgs.media.returnYourTeamSound ); else CG_AddBufferedSound( cgs.media.returnOpponentSound ); // CG_AddBufferedSound( cgs.media.blueFlagReturnedSound ); break; case GTS_BLUE_RETURN: // CTF red flag returned, 1FCTF: neutral flag returned if ( blueTeam ) CG_AddBufferedSound( cgs.media.returnYourTeamSound ); else CG_AddBufferedSound( cgs.media.returnOpponentSound ); // CG_AddBufferedSound( cgs.media.redFlagReturnedSound ); break; case GTS_RED_TAKEN: // CTF: red team took blue flag, 1FCTF: blue team took the neutral flag // if this player picked up the flag then a sound is played in CG_CheckLocalSounds if (localHasBlue || localHasNeutral) { } else if (!(redTeam && blueTeam)) { if (blueTeam) { #ifdef MISSIONPACK if (cgs.gametype == GT_1FCTF) CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound ); else #endif CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound ); } else if (redTeam) { #ifdef MISSIONPACK if (cgs.gametype == GT_1FCTF) CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound ); else #endif CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound ); } } else { // ZTM: NOTE: There are local players on both teams, so have no correct sound to play. New games should fix this. } break; case GTS_BLUE_TAKEN: // CTF: blue team took the red flag, 1FCTF red team took the neutral flag // if this player picked up the flag then a sound is played in CG_CheckLocalSounds if (localHasRed || localHasNeutral) { } else if (!(redTeam && blueTeam)) { if (redTeam) { #ifdef MISSIONPACK if (cgs.gametype == GT_1FCTF) CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound ); else #endif CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound ); } else if (blueTeam) { #ifdef MISSIONPACK if (cgs.gametype == GT_1FCTF) CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound ); else #endif CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound ); } } else { // ZTM: NOTE: There are local players on both teams, so have no correct sound to play. New games should fix this. } break; #ifdef MISSIONPACK // ZTM: NOTE: These are confusing when there are players on both teams (players don't know which base is attacked). New games should fix this. case GTS_REDOBELISK_ATTACKED: // Overload: red obelisk is being attacked if (redTeam) { CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound ); } break; case GTS_BLUEOBELISK_ATTACKED: // Overload: blue obelisk is being attacked if (blueTeam) { CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound ); } break; #endif case GTS_REDTEAM_SCORED: CG_AddBufferedSound(cgs.media.redScoredSound); break; case GTS_BLUETEAM_SCORED: CG_AddBufferedSound(cgs.media.blueScoredSound); break; case GTS_REDTEAM_TOOK_LEAD: if ( cgs.gametype != GT_TEAM || cg_teamDmLeadAnnouncements.integer ) { CG_AddBufferedSound(cgs.media.redLeadsSound); } break; case GTS_BLUETEAM_TOOK_LEAD: if ( cgs.gametype != GT_TEAM || cg_teamDmLeadAnnouncements.integer ) { CG_AddBufferedSound(cgs.media.blueLeadsSound); } break; case GTS_TEAMS_ARE_TIED: if ( cgs.gametype != GT_TEAM || cg_teamDmLeadAnnouncements.integer ) { CG_AddBufferedSound( cgs.media.teamsTiedSound ); } break; #ifdef MISSIONPACK case GTS_KAMIKAZE: trap_S_StartLocalSound(cgs.media.kamikazeFarSound, CHAN_ANNOUNCER); break; #endif default: break; } break; } case EV_PAIN: // local player sounds are triggered in CG_CheckLocalSounds, // so ignore events on the player DEBUGNAME("EV_PAIN"); if ( !CG_LocalPlayerState( es->number ) ) { CG_PainEvent( cent, es->eventParm ); } break; case EV_DEATH1: case EV_DEATH2: case EV_DEATH3: DEBUGNAME2("EV_DEATH%d", event - EV_DEATH1 + 1); // check if gibbed // eventParm 1 = living player gibbed // eventParm 2 = corpse gibbed // eventParm 3 = living person gib headshot if ( es->eventParm >= 1 ) { CG_GibPlayer( cent->lerpOrigin, (es->eventParm == 3) ? qtrue : qfalse ); if ( cg_blood.integer && cg_gibs.integer ) { // don't play gib sound when using the kamikaze because it interferes // with the kamikaze sound, downside is that the gib sound will also // not be played when someone is gibbed while just carrying the kamikaze if ( !(es->eFlags & EF_KAMIKAZE) ) { trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.gibSound ); } // don't play death sound break; } // don't play death sound if already dead if ( es->eventParm == 2 ) { break; } } if (CG_WaterLevel(cent) >= 1) { trap_S_StartSound(NULL, es->number, CHAN_VOICE, CG_CustomSound(es->number, "*drown.wav")); } else { 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"); CG_ParseObituary( es ); break; // // powerup events // case EV_POWERUP_QUAD: DEBUGNAME("EV_POWERUP_QUAD"); for (i = 0; i < CG_MaxSplitView(); i++) { if ( es->number == cg.snap->pss[i].playerNum ) { cg.localPlayers[i].powerupActive = PW_QUAD; cg.localPlayers[i].powerupTime = cg.time; } } trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.quadSound ); break; case EV_POWERUP_BATTLESUIT: DEBUGNAME("EV_POWERUP_BATTLESUIT"); for (i = 0; i < CG_MaxSplitView(); i++) { if ( es->number == cg.snap->pss[i].playerNum ) { cg.localPlayers[i].powerupActive = PW_BATTLESUIT; cg.localPlayers[i].powerupTime = cg.time; } } trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.protectSound ); break; case EV_POWERUP_REGEN: DEBUGNAME("EV_POWERUP_REGEN"); for (i = 0; i < CG_MaxSplitView(); i++) { if ( es->number == cg.snap->pss[i].playerNum ) { cg.localPlayers[i].powerupActive = PW_REGEN; cg.localPlayers[i].powerupTime = cg.time; } } trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.regenSound ); break; case EV_STOPLOOPINGSOUND: DEBUGNAME("EV_STOPLOOPINGSOUND"); trap_S_StopLoopingSound( es->number ); es->loopSound = 0; break; case EV_DEBUG_LINE: DEBUGNAME("EV_DEBUG_LINE"); CG_Beam( cent ); break; default: DEBUGNAME("UNKNOWN"); CG_Error( "Unknown event: %i", event ); break; } }
/* ================= CG_DrawPlayerScore ================= */ static void CG_DrawPlayerScore( int y, score_t *score, float *color, float fade, qboolean largeFormat ) { char string[1024]; vec3_t headAngles; playerInfo_t *pi; int iconx, headx; playerState_t *ps; if ( score->playerNum < 0 || score->playerNum >= cgs.maxplayers ) { Com_Printf( "Bad score->playerNum: %i\n", score->playerNum ); return; } pi = &cgs.playerinfo[score->playerNum]; iconx = SB_BOTICON_X + (SB_RATING_WIDTH / 2); headx = SB_HEAD_X + (SB_RATING_WIDTH / 2); // draw the handicap or bot skill marker (unless player has flag) if ( pi->powerups & ( 1 << PW_NEUTRALFLAG ) ) { if( largeFormat ) { CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_FREE, qfalse ); } else { CG_DrawFlagModel( iconx, y, 16, 16, TEAM_FREE, qfalse ); } } else if ( pi->powerups & ( 1 << PW_REDFLAG ) ) { if( largeFormat ) { CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_RED, qfalse ); } else { CG_DrawFlagModel( iconx, y, 16, 16, TEAM_RED, qfalse ); } } else if ( pi->powerups & ( 1 << PW_BLUEFLAG ) ) { if( largeFormat ) { CG_DrawFlagModel( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, TEAM_BLUE, qfalse ); } else { CG_DrawFlagModel( iconx, y, 16, 16, TEAM_BLUE, qfalse ); } } else { if ( pi->botSkill > 0 && pi->botSkill <= 5 ) { if ( cg_drawIcons.integer ) { if( largeFormat ) { CG_DrawPic( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, cgs.media.botSkillShaders[ pi->botSkill - 1 ] ); } else { CG_DrawPic( iconx, y, 16, 16, cgs.media.botSkillShaders[ pi->botSkill - 1 ] ); } } } else if ( pi->handicap < 100 ) { Com_sprintf( string, sizeof( string ), "%i", pi->handicap ); if ( cgs.gametype == GT_TOURNAMENT ) { CG_DrawString( iconx, y - SMALLCHAR_HEIGHT/2, string, UI_SMALLFONT|UI_NOSCALE, color ); } else { CG_DrawString( iconx, y, string, UI_SMALLFONT|UI_NOSCALE, color ); } } // draw the wins / losses if ( cgs.gametype == GT_TOURNAMENT ) { Com_sprintf( string, sizeof( string ), "%i/%i", pi->wins, pi->losses ); if( pi->handicap < 100 && !pi->botSkill ) { CG_DrawString( iconx, y + SMALLCHAR_HEIGHT/2, string, UI_SMALLFONT|UI_NOSCALE, color ); } else { CG_DrawString( iconx, y, string, UI_SMALLFONT|UI_NOSCALE, color ); } } } // draw the face VectorClear( headAngles ); headAngles[YAW] = 180; if( largeFormat ) { CG_DrawHead( headx, y - ( ICON_SIZE - BIGCHAR_HEIGHT ) / 2, ICON_SIZE, ICON_SIZE, score->playerNum, headAngles ); } else { CG_DrawHead( headx, y, 16, 16, score->playerNum, headAngles ); } #ifdef MISSIONPACK // draw the team task switch ( pi->teamTask ) { case TEAMTASK_OFFENSE: CG_DrawPic( headx + 48, y, 16, 16, cgs.media.assaultShader ); break; case TEAMTASK_DEFENSE: CG_DrawPic( headx + 48, y, 16, 16, cgs.media.defendShader ); break; case TEAMTASK_PATROL: CG_DrawPic( headx + 48, y, 16, 16, cgs.media.patrolShader ); break; case TEAMTASK_FOLLOW: CG_DrawPic( headx + 48, y, 16, 16, cgs.media.followShader ); break; case TEAMTASK_CAMP: CG_DrawPic( headx + 48, y, 16, 16, cgs.media.campShader ); break; case TEAMTASK_RETRIEVE: CG_DrawPic( headx + 48, y, 16, 16, cgs.media.retrieveShader ); break; case TEAMTASK_ESCORT: CG_DrawPic( headx + 48, y, 16, 16, cgs.media.escortShader ); break; default: break; } #endif if (cg.cur_ps) { if (score->playerNum == cg.cur_ps->playerNum) { ps = cg.cur_ps; } else { ps = NULL; } } else { ps = CG_LocalPlayerState(score->playerNum); } // highlight your position if ( ps ) { float hcolor[4]; int rank; localPlayer = qtrue; if ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR || cgs.gametype >= GT_TEAM ) { rank = -1; } else { rank = ps->persistant[PERS_RANK] & ~RANK_TIED_FLAG; } if ( rank == 0 ) { hcolor[0] = 0; hcolor[1] = 0; hcolor[2] = 0.7f; } else if ( rank == 1 ) { hcolor[0] = 0.7f; hcolor[1] = 0; hcolor[2] = 0; } else if ( rank == 2 ) { hcolor[0] = 0.7f; hcolor[1] = 0.7f; hcolor[2] = 0; } else { hcolor[0] = 0.7f; hcolor[1] = 0.7f; hcolor[2] = 0.7f; } hcolor[3] = fade * 0.7; CG_FillRect( SB_SCORELINE_X + BIGCHAR_WIDTH + (SB_RATING_WIDTH / 2), y, 640 - SB_SCORELINE_X - BIGCHAR_WIDTH - (SB_RATING_WIDTH / 2), BIGCHAR_HEIGHT+1, hcolor ); } // draw the score line if ( score->ping == -1 ) { Com_sprintf(string, sizeof(string), "connecting"); } else if ( pi->team == TEAM_SPECTATOR ) { Com_sprintf(string, sizeof(string), "SPECT"); } else { Com_sprintf(string, sizeof(string), "%5i", score->score); } CG_DrawString( SB_SCORE_X + (SB_RATING_WIDTH / 2) + 4*BIGCHAR_WIDTH, y, string, UI_RIGHT|UI_DROPSHADOW|UI_BIGFONT|UI_NOSCALE, color ); if ( score->ping != -1 ) { Com_sprintf(string, sizeof(string), "%4i", score->ping); CG_DrawString( SB_PING_X - (SB_RATING_WIDTH / 2) + 4*BIGCHAR_WIDTH, y, string, UI_RIGHT|UI_DROPSHADOW|UI_BIGFONT|UI_NOSCALE, color ); Com_sprintf(string, sizeof(string), "%4i", score->time); CG_DrawString( SB_TIME_X - (SB_RATING_WIDTH / 2) + 4*BIGCHAR_WIDTH, y, string, UI_RIGHT|UI_DROPSHADOW|UI_BIGFONT|UI_NOSCALE, color ); } CG_DrawString( SB_NAME_X - (SB_RATING_WIDTH / 2), y, pi->name, UI_LEFT|UI_DROPSHADOW|UI_BIGFONT|UI_NOSCALE, color ); // add the "ready" marker for intermission exiting if ( Com_ClientListContains( &cg.readyPlayers, score->playerNum ) ) { CG_DrawString( iconx, y, "READY", UI_LEFT|UI_DROPSHADOW|UI_BIGFONT|UI_NOSCALE, color ); } }