/* ================ CG_FragmentBounceSound ================ */ void CG_FragmentBounceSound( localEntity_t *le, trace_t *trace ) { if ( le->leBounceSoundType == LEBS_BLOOD ) { // half the gibs will make splat sounds if ( rand() & 1 ) { int r = rand()&3; sfxHandle_t s; if ( r == 0 ) { s = cgs.media.gibBounce1Sound; } else if ( r == 1 ) { s = cgs.media.gibBounce2Sound; } else { s = cgs.media.gibBounce3Sound; } trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s ); } } else if ( le->leBounceSoundType == LEBS_BRASS ) { if ( cg_leiBrassNoise.integer ) { // half the casings will make casing sounds if ( rand() & 1 ) { int r = rand()&3; sfxHandle_t s; if ( r == 0 ) { s = cgs.media.lbul1Sound; } else if ( r == 1 ) { s = cgs.media.lbul2Sound; } else { s = cgs.media.lbul3Sound; } trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s ); } } } else if ( le->leBounceSoundType == LEBS_SHELL ) { if ( cg_leiBrassNoise.integer ) { // half the casings will make casing sounds if ( rand() & 1 ) { int r = rand()&3; sfxHandle_t s; if ( r == 0 ) { s = cgs.media.lshl1Sound; } else if ( r == 1 ) { s = cgs.media.lshl2Sound; } else { s = cgs.media.lshl3Sound; } trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s ); } } } // don't allow a fragment to make multiple bounce sounds, // or it gets too noisy as they settle le->leBounceSoundType = LEBS_NONE; }
/* ================ 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.wav"; } else if ( health < 50 ) { snd = "*pain50_1.wav"; } else if ( health < 75 ) { snd = "*pain75_1.wav"; } else { snd = "*pain100_1.wav"; } // play a gurp sound instead of a normal pain sound if (CG_WaterLevel(cent) >= 1) { if (rand()&1) { trap_S_StartSound(NULL, cent->currentState.number, CHAN_VOICE, CG_CustomSound(cent->currentState.number, "sound/player/gurp1.wav")); } else { trap_S_StartSound(NULL, cent->currentState.number, CHAN_VOICE, CG_CustomSound(cent->currentState.number, "sound/player/gurp2.wav")); } } else { 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_FragmentBounceSound ================ */ void CG_FragmentBounceSound(localEntity_t * le, trace_t * trace) { if (le->leBounceSoundType == LEBS_BLOOD) { // half the gibs will make splat sounds if (rand() & 1) { int r = rand() & 3; sfxHandle_t s; if (r == 0) { s = cgs.media.gibBounce1Sound; } else if (r == 1) { s = cgs.media.gibBounce2Sound; } else { s = cgs.media.gibBounce3Sound; } trap_S_StartSound(trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s); } } else if (le->leBounceSoundType == LEBS_BRASS) { // Elder: play bounce sound trap_S_StartSound(trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.sfx_shelltumble); } // don't allow a fragment to make multiple bounce sounds, // or it gets too noisy as they settle le->leBounceSoundType = LEBS_NONE; }
/* =============== CG_UseItem =============== */ static void CG_UseItem( centity_t *cent ) { playerInfo_t *pi; int itemNum, playerNum; gitem_t *item; entityState_t *es; int i; es = ¢->currentState; itemNum = (es->event & ~EV_EVENT_BITS) - EV_USE_ITEM0; if ( itemNum < 0 || itemNum > HI_NUM_HOLDABLE ) { itemNum = 0; } // print a message if the local player for (i = 0; i < CG_MaxSplitView(); i++) { if ( es->number != cg.snap->pss[i].playerNum ) { continue; } if ( !itemNum ) { CG_CenterPrint( i, "No item to use", SCREEN_HEIGHT * 0.30, 0.5 ); } else { item = BG_FindItemForHoldable( itemNum ); CG_CenterPrint( i, va("Use %s", item->pickup_name), SCREEN_HEIGHT * 0.30, 0.5 ); } } switch ( itemNum ) { default: case HI_NONE: trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useNothingSound ); break; case HI_TELEPORTER: break; case HI_MEDKIT: playerNum = cent->currentState.playerNum; if ( playerNum >= 0 && playerNum < MAX_CLIENTS ) { pi = &cgs.playerinfo[ playerNum ]; pi->medkitUsageTime = cg.time; } trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.medkitSound ); break; #ifdef MISSIONPACK case HI_KAMIKAZE: break; case HI_PORTAL: break; case HI_INVULNERABILITY: trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useInvulnerabilitySound ); break; #endif } }
/* =============== CG_UseItem =============== */ static void CG_UseItem( centity_t *cent ) { clientInfo_t *ci; int itemNum, clientNum; gitem_t *item; entityState_t *es; es = ¢->currentState; itemNum = (es->event & ~EV_EVENT_BITS) - EV_USE_ITEM0; if ( itemNum < 0 || itemNum > HI_NUM_HOLDABLE ) { itemNum = 0; } // print a message if the local player if ( es->number == cg.snap->ps.clientNum ) { if ( !itemNum ) { CG_CenterPrint( "No item to use", SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); } else { item = BG_FindItemForHoldable( itemNum ); CG_CenterPrint( va("Use %s", item->pickup_name), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); } } switch ( itemNum ) { default: case HI_NONE: trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useNothingSound ); break; case HI_TELEPORTER: break; case HI_MEDKIT: clientNum = cent->currentState.clientNum; if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) { ci = &cgs.clientinfo[ clientNum ]; ci->medkitUsageTime = cg.time; } trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.medkitSound ); break; #ifdef MISSIONPACK case HI_KAMIKAZE: break; case HI_PORTAL: break; case HI_INVULNERABILITY: trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useInvulnerabilitySound ); break; #endif } }
/* ================ 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.wav"; } else if ( health < 50 ) { snd = "*pain50_1.wav"; } else if ( health < 75 ) { snd = "*pain75_1.wav"; } else { snd = "*pain100_1.wav"; } 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_SoundPickOldestRandomSound ============== */ void CG_SoundPickOldestRandomSound( soundScript_t *sound, vec3_t org, int entnum ) { int oldestTime = 0; // TTimo: init soundScriptSound_t *oldestSound; soundScriptSound_t *scriptSound; oldestSound = NULL; scriptSound = sound->soundList; while ( scriptSound ) { if ( !oldestSound || ( scriptSound->lastPlayed < oldestTime ) ) { oldestTime = scriptSound->lastPlayed; oldestSound = scriptSound; } scriptSound = scriptSound->next; } if ( oldestSound ) { // play this sound if ( !sound->streaming ) { if ( !oldestSound->sfxHandle ) { oldestSound->sfxHandle = trap_S_RegisterSound( oldestSound->filename ); } trap_S_StartSound( org, entnum, sound->channel, oldestSound->sfxHandle ); } else { trap_S_StartStreamingSound( oldestSound->filename, sound->looping ? oldestSound->filename : NULL, entnum, sound->channel, sound->attenuation ); } oldestSound->lastPlayed = cg.time; } else { CG_Error( "Unable to locate a valid sound for soundScript: %s\n", sound->name ); } }
/* ================ CG_SplatSound LEILEI ================ */ void CG_SplatSound( localEntity_t *le, trace_t *trace ) { if ( le->leBounceSoundType == LEBS_BLOOD ) { // half the splats will make splat sounds if ( cg_leiGoreNoise.integer ) { if ( rand() & 1 ) { int r = rand()&3; sfxHandle_t s; if ( r == 0 ) { s = cgs.media.lspl1Sound; } else if ( r == 1 ) { s = cgs.media.lspl2Sound; } else { s = cgs.media.lspl3Sound; } trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s ); } } } else if ( le->leBounceSoundType == LEBS_BRASS ) { // no GERMAN EURO CENSOR ROBOTS mode yet. } // don't allow a fragment to make multiple bounce sounds, // or it gets too noisy as they settle le->leBounceSoundType = LEBS_NONE; }
void CG_PMItemBigSound( pmListItemBig_t* item ) { if ( !cg.snap ) { return; } switch ( item->type ) { case PM_RANK: trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.media.sndRankUp ); break; case PM_SKILL: trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.media.sndSkillUp ); break; default: break; } }
qboolean GrenadeBeep(localEntity_t *le) { weaponInfo_t *weaponInfo = &cg_weapons[WP_8]; trap_S_StartSound(le->refEntity.origin, ENTITYNUM_WORLD, CHAN_AUTO, weaponInfo->altHitSound); return qtrue; }
/* ================== CG_InvulnerabilityJuiced ================== */ void CG_InvulnerabilityJuiced( vec3_t org ) { localEntity_t *le; refEntity_t *re; vec3_t angles; le = CG_AllocLocalEntity(); le->leFlags = 0; le->leType = LE_INVULJUICED; le->startTime = cg.time; le->endTime = cg.time + 10000; le->lifeRate = 1.0 / ( le->endTime - le->startTime ); le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0; re = &le->refEntity; re->reType = RT_MODEL; re->shaderTime = cg.time / 1000.0f; re->hModel = cgs.media.invulnerabilityJuicedModel; VectorCopy( org, re->origin ); VectorClear(angles); AnglesToAxis( angles, re->axis ); trap_S_StartSound (org, ENTITYNUM_NONE, CHAN_BODY, cgs.media.invulnerabilityJuicedSound ); }
/* ================== CG_InvulnerabilityImpact ================== */ void CG_InvulnerabilityImpact( vec3_t org, vec3_t angles ) { localEntity_t *le; refEntity_t *re; int r; sfxHandle_t sfx; le = CG_AllocLocalEntity(); le->leFlags = 0; le->leType = LE_INVULIMPACT; le->startTime = cg.time; le->endTime = cg.time + 1000; le->lifeRate = 1.0 / ( le->endTime - le->startTime ); le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0; re = &le->refEntity; re->reType = RT_MODEL; re->shaderTime = cg.time / 1000.0f; re->hModel = cgs.media.invulnerabilityImpactModel; VectorCopy( org, re->origin ); AnglesToAxis( angles, re->axis ); r = rand() & 3; if ( r < 2 ) { sfx = cgs.media.invulnerabilityImpactSound1; } else if ( r == 2 ) { sfx = cgs.media.invulnerabilityImpactSound2; } else { sfx = cgs.media.invulnerabilityImpactSound3; } trap_S_StartSound (org, ENTITYNUM_NONE, CHAN_BODY, sfx ); }
/* ================ CG_FragmentBounceSound ================ */ void CG_FragmentBounceSound( localEntity_t *le, trace_t *trace ) { if ( le->leBounceSoundType == LEBS_BLOOD ) { // half the gibs will make splat sounds if ( rand() & 1 ) { int r = rand()&3; sfxHandle_t s; if ( r < 2 ) { s = cgs.media.gibBounce1Sound; } else if ( r == 2 ) { s = cgs.media.gibBounce2Sound; } else { s = cgs.media.gibBounce3Sound; } trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s ); } } else if ( le->leBounceSoundType == LEBS_BRASS ) { //----(SA) added } else if ( le->leBounceSoundType == LEBS_ROCK ) { // half the hits will make thunk sounds (this is just to start since we don't even have the sound yet... (SA)) if ( rand() & 1 ) { int r = rand()&3; sfxHandle_t s; if ( r < 2 ) { s = cgs.media.debBounce1Sound; } else if ( r == 2 ) { s = cgs.media.debBounce2Sound; } else { s = cgs.media.debBounce3Sound; } trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s ); } //----(SA) end } else if ( le->leBounceSoundType == LEBS_BONE ) { trap_S_StartSound( trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.boneBounceSound ); } // don't allow a fragment to make multiple bounce sounds, // or it gets too noisy as they settle le->leBounceSoundType = LEBS_NONE; }
/* =============== CG_TransitionPlayerState =============== */ void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ) { // check for changing follow mode if( ps->clientNum != ops->clientNum ) { cg.thisFrameTeleport = qtrue; // make sure we don't get any unwanted transition effects *ops = *ps; CG_ResetPainBlend( ); } // damage events (player is getting wounded) if( ps->damageEvent != ops->damageEvent && ps->damageCount ) CG_DamageFeedback( ps->damageYaw, ps->damagePitch, ps->damageCount ); // respawning if( ps->persistant[ PERS_SPAWN_COUNT ] != ops->persistant[ PERS_SPAWN_COUNT ] ) CG_Respawn( ); if( cg.mapRestart ) { CG_Respawn( ); cg.mapRestart = qfalse; } if( cg.snap->ps.pm_type != PM_INTERMISSION && ps->persistant[ PERS_SPECSTATE ] == SPECTATOR_NOT ) CG_CheckLocalSounds( ps, ops ); // run events CG_CheckPlayerstateEvents( ps, ops ); // smooth the ducking viewheight change if( ps->viewheight != ops->viewheight ) { cg.duckChange = ps->viewheight - ops->viewheight; cg.duckTime = cg.time; } // changed team if( ps->stats[ STAT_TEAM ] != ops->stats[ STAT_TEAM ] ) { cg.lastHealthCross = 0; cg.chargeMeterAlpha = 0.0f; } if( ps->stats[ STAT_FUEL ] < JETPACK_FUEL_JUMP && ops->stats[ STAT_FUEL ] >= JETPACK_FUEL_JUMP && cg.predictedPlayerEntity.jetPackJumpTime + 1000 > cg.time ) { trap_S_StartSound( NULL, cg.predictedPlayerState.clientNum, CHAN_AUTO, cgs.media.jetpackNoJumpFuelSound ); } }
/* =============== CG_UseItem =============== */ static void CG_UseItem( centity_t *cent ) { clientInfo_t *ci = 0; int itemNum; gitem_t *item; entityState_t *es; es = ¢->currentState; itemNum = (es->event & ~EV_EVENT_BITS) - EV_USE_ITEM0; if ( itemNum < 0 || itemNum > HI_NUM_HOLDABLE ) { itemNum = 0; } // print a message if the local player if ( es->number == cg.snap->ps.clientNum ) { if ( !itemNum ) { CG_CenterPrint( "No item to use" ); } else { item = BG_FindItemForHoldable( itemNum ); CG_CenterPrint( va("Use %s", item->pickup_name) ); } } switch ( itemNum ) { default: case HI_NONE: trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.useNothingSound ); break; case HI_TELEPORTER: break; case HI_MEDKIT: trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.medkitSound ); break; } }
/* ================== CG_GlassShatter_Old Throws glass shards from within a given bounding box in the world ================== */ void CG_GlassShatter_Old(int entnum, vector3 *org, vector3 *mins, vector3 *maxs) { vector3 velocity, a, shardorg, dif, difx; float windowmass; float shardsthrow = 0; char chunkname[256]; trap_S_StartSound(org, entnum, CHAN_BODY, trap_S_RegisterSound("sound/effects/glassbreak1.wav")); VectorSubtract(maxs, mins, &a); windowmass = VectorLength(&a); //should give us some idea of how big the chunk of glass is while (shardsthrow < windowmass) { velocity.x = crandom()*150; velocity.y = crandom()*150; velocity.z = 150 + crandom()*75; Com_sprintf(chunkname, sizeof(chunkname), "models/chunks/glass/glchunks_%i.md3", Q_irand(1, 6)); VectorCopy(org, &shardorg); dif.x = (maxs->x-mins->x)/2; dif.y = (maxs->y-mins->y)/2; dif.z = (maxs->z-mins->z)/2; if (dif.x < 2) dif.x = 2; if (dif.y < 2) dif.y = 2; if (dif.z < 2) dif.z = 2; difx.x = Q_irand(1, (dif.x*0.9)*2); difx.y = Q_irand(1, (dif.y*0.9)*2); difx.z = Q_irand(1, (dif.z*0.9)*2); if (difx.x > dif.x) shardorg.x += difx.x-(dif.x); else shardorg.x -= difx.x; if (difx.y > dif.y) shardorg.y += difx.y-(dif.y); else shardorg.y -= difx.y; if (difx.z > dif.z) shardorg.z += difx.z-(dif.z); else shardorg.z -= difx.z; //CG_TestLine(org, shardorg, 5000, 0x0000ff, 3); CG_ThrowChunk( &shardorg, &velocity, trap_R_RegisterModel( chunkname ), 0, 254 ); shardsthrow += 10; } }
/* ================ CG_FireWeapon Caused by an EV_FIRE_WEAPON event ================ */ void CG_FireWeapon( centity_t *cent, weaponMode_t weaponMode ) { entityState_t *es; int c; weaponInfo_t *wi; weapon_t weaponNum; es = ¢->currentState; weaponNum = es->weapon; if( weaponNum == WP_NONE ) return; if( weaponMode <= WPM_NONE || weaponMode >= WPM_NUM_WEAPONMODES ) weaponMode = WPM_PRIMARY; if( weaponNum >= WP_NUM_WEAPONS ) { CG_Error( "CG_FireWeapon: ent->weapon >= WP_NUM_WEAPONS" ); return; } wi = &cg_weapons[ weaponNum ]; // mark the entity as muzzle flashing, so when it is added it will // append the flash to the weapon model cent->muzzleFlashTime = cg.time; if( wi->wim[ weaponMode ].muzzleParticleSystem ) { if( !CG_IsParticleSystemValid( ¢->muzzlePS ) || !CG_IsParticleSystemInfinite( cent->muzzlePS ) ) cent->muzzlePsTrigger = qtrue; } // play a sound for( c = 0; c < 4; c++ ) { if( !wi->wim[ weaponMode ].flashSound[ c ] ) break; } if( c > 0 ) { c = rand( ) % c; if( wi->wim[ weaponMode ].flashSound[ c ] ) trap_S_StartSound( NULL, es->number, CHAN_WEAPON, wi->wim[ weaponMode ].flashSound[ c ] ); } }
/* ================== CG_ObeliskPain ================== */ void CG_ObeliskPain( vec3_t org ) { float r; sfxHandle_t sfx; // hit sound r = rand() & 3; if ( r < 2 ) { sfx = cgs.media.obeliskHitSound1; } else if ( r == 2 ) { sfx = cgs.media.obeliskHitSound2; } else { sfx = cgs.media.obeliskHitSound3; } trap_S_StartSound ( org, ENTITYNUM_NONE, CHAN_BODY, sfx ); }
/* ============== CG_SoundPickOldestRandomSound ============== */ void CG_SoundPickOldestRandomSound( soundScript_t *sound, vec3_t org, int entnum ) { int oldestTime = 0; // TTimo: init soundScriptSound_t *oldestSound; soundScriptSound_t *scriptSound; vec3_t eOrg; oldestSound = NULL; scriptSound = sound->soundList; while ( scriptSound ) { if ( !oldestSound || ( scriptSound->lastPlayed < oldestTime ) ) { oldestTime = scriptSound->lastPlayed; oldestSound = scriptSound; } scriptSound = scriptSound->next; } if ( oldestSound ) { // play this sound if ( !sound->streaming ) { if ( !oldestSound->sfxHandle ) { oldestSound->sfxHandle = trap_S_RegisterSound( oldestSound->filename ); } if ( sound->attenuation ) { trap_S_StartSound( org, entnum, sound->channel, oldestSound->sfxHandle ); } else { trap_S_StartLocalSound( oldestSound->sfxHandle, sound->channel ); } } else { trap_S_StartStreamingSound( oldestSound->filename, sound->looping ? oldestSound->filename : NULL, entnum, sound->channel, sound->attenuation ); } oldestSound->lastPlayed = cg.time; // // shake the view? if ( sound->shakeScale ) { // get the origin if ( org ) { VectorCopy( org, eOrg ); } else { VectorCopy( cg_entities[entnum].lerpOrigin, eOrg ); } // // start the shaker CG_StartShakeCamera( sound->shakeScale, sound->shakeDuration, eOrg, sound->shakeRadius ); } } else { CG_Error( "Unable to locate a valid sound for soundScript: %s\n", sound->name ); } }
/* ================= CG_HumanBuildableExplosion Called for human buildables as they are destroyed ================= */ void CG_HumanBuildableExplosion( vec3_t origin, vec3_t dir ) { particleSystem_t *ps; trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.humanBuildableExplosion ); //particle system ps = CG_SpawnNewParticleSystem( cgs.media.humanBuildableDestroyedPS ); if( CG_IsParticleSystemValid( &ps ) ) { CG_SetAttachmentPoint( &ps->attachment, origin ); CG_SetParticleSystemNormal( ps, dir ); CG_AttachToPoint( &ps->attachment ); } }
/* ===================== CG_PowerupTimerSounds ===================== */ static void CG_PowerupTimerSounds( void ) { int i; int t; // powerup timers going away for ( i = 0 ; i < MAX_POWERUPS ; i++ ) { t = cg.snap->ps.powerups[i]; if ( t <= cg.time ) { continue; } if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) { continue; } if ( ( t - cg.time ) / POWERUP_BLINK_TIME != ( t - cg.oldTime ) / POWERUP_BLINK_TIME ) { trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_ITEM, cgs.media.wearOffSound ); } } }
/* =============== CG_RunBuildableLerpFrame Sets cg.snap, cg.oldFrame, and cg.backlerp cg.time should be between oldFrameTime and frameTime after exit =============== */ static void CG_RunBuildableLerpFrame( centity_t *cent ) { buildable_t buildable = cent->currentState.modelindex; lerpFrame_t *lf = ¢->lerpFrame; buildableAnimNumber_t newAnimation = cent->buildableAnim & ~( ANIM_TOGGLEBIT|ANIM_FORCEBIT ); // see if the animation sequence is switching if( newAnimation != lf->animationNumber || !lf->animation ) { if( cg_debugRandom.integer ) CG_Printf( "newAnimation: %d lf->animationNumber: %d lf->animation: %d\n", newAnimation, lf->animationNumber, lf->animation ); CG_SetBuildableLerpFrameAnimation( buildable, lf, newAnimation ); if( !cg_buildables[ buildable ].sounds[ newAnimation ].looped && cg_buildables[ buildable ].sounds[ newAnimation ].enabled ) { if( cg_debugRandom.integer ) CG_Printf( "Sound for animation %d for a %s\n", newAnimation, BG_Buildable( buildable )->humanName ); trap_S_StartSound( cent->lerpOrigin, cent->currentState.number, CHAN_AUTO, cg_buildables[ buildable ].sounds[ newAnimation ].sound ); } } if( cg_buildables[ buildable ].sounds[ lf->animationNumber ].looped && cg_buildables[ buildable ].sounds[ lf->animationNumber ].enabled ) trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cg_buildables[ buildable ].sounds[ lf->animationNumber ].sound ); CG_RunLerpFrame( lf, 1.0f ); // animation ended if( lf->frameTime == cg.time ) { cent->buildableAnim = cent->currentState.torsoAnim; cent->buildableIdleAnim = qtrue; } }
void FX_GrenadeExplode( vec3_t origin, vec3_t normal ) { localEntity_t *le; qhandle_t null = 0; vec3_t direction, org, vel; int i; VectorSet( direction, 0,0,1 ); // Add an explosion and tag a light to it le = CG_MakeExplosion2( origin, direction, cgs.media.nukeModel, 5, null, 250, qfalse, 25.0f, LEF_FADE_RGB); le->light = 150; le->refEntity.renderfx |= RF_NOSHADOW; VectorSet( le->lightColor, 1.0f, 0.6f, 0.2f ); // Ground ring FX_AddQuad( origin, normal, 5, 100, 1.0, 0.0, random() * 360, 300, cgs.media.bigShockShader ); // Flare VectorMA( origin, 12, direction, org ); FX_AddSprite( org, NULL, qfalse, 160.0, -160.0, 1.0, 0.0, 0.0, 0.0, 200, cgs.media.sunnyFlareShader );//, FXF_NON_LINEAR_FADE ); for (i = 0; i < 12; i++) { float width, length; FXE_Spray( normal, 470, 325, 0.5f, vel); length = 24.0 + random() * 12; width = 0.5 + random() * 2; FX_AddTrail( origin, vel, qtrue, length, -length, width, -width, 1.0f, 1.0f, 0.5f, 1000.0f, cgs.media.orangeTrailShader); } trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeExplodeSound ); // Smoke and impact // FX_AddSpawner( origin, normal, NULL, NULL, 100, 25.0f, 2000.0f, (void *) CG_SmokeSpawn, NULL, 1024 ); CG_ImpactMark( cgs.media.compressionMarkShader, origin, normal, random()*360, 1,1,1,1.0, qfalse, random() * 16 + 48, qfalse ); }
void nox_trap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ) { int doit = 1; //consider NonX (lmo) if ( cg.snap->ps.duelInProgress ) { // this client is dueling if ( entityNum >= 0 && entityNum < MAX_CLIENTS && entityNum != cg.snap->ps.clientNum && entityNum != cg.snap->ps.duelIndex ) { // sound originated from a client, but not one of the duelers doit = 0; } else if ( entityNum >= MAX_CLIENTS && cg_entities[entityNum].currentState.otherEntityNum != ENTITYNUM_NONE && cg_entities[entityNum].currentState.otherEntityNum != cg.snap->ps.clientNum && cg_entities[entityNum].currentState.otherEntityNum != cg.snap->ps.duelIndex ) { // sound generated by non-client (e.g. temp) entity in a snap, the otherEntityNum should be the orinating // client number (by hack!). If otherEntityNum is ENTITYNUM_NONE, then it is one of the many sounds // I don't bother filtering, so play it. Otherwise, if not from the duelers, supress it doit = 0; } } if ( doit ) { trap_S_StartSound( origin, entityNum, entchannel, sfx ); } }
/* ============== CG_EntityEvent An entity has an event value also called by CG_CheckPlayerstateEvents ============== */ 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; int steptime; if ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT ) { steptime = 200; } else { steptime = BG_Class( cg.snap->ps.stats[ STAT_CLASS ] )->steptime; } es = ¢->currentState; event = es->event & ~EV_EVENT_BITS; if ( cg_debugEvents.integer ) { CG_Printf( "ent:%3i event:%3i %s\n", es->number, event, BG_EventName( event ) ); } if ( !event ) { return; } clientNum = es->clientNum; if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) { clientNum = 0; } ci = &cgs.clientinfo[ clientNum ]; switch ( event ) { case EV_FOOTSTEP: if ( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE ) { if ( ci->footsteps == FOOTSTEP_CUSTOM ) { trap_S_StartSound( NULL, es->number, CHAN_BODY, ci->customFootsteps[ rand() & 3 ] ); } else { trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.footsteps[ ci->footsteps ][ rand() & 3 ] ); } } break; case EV_FOOTSTEP_METAL: if ( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE ) { if ( ci->footsteps == FOOTSTEP_CUSTOM ) { trap_S_StartSound( NULL, es->number, CHAN_BODY, ci->customMetalFootsteps[ rand() & 3 ] ); } else { trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_METAL ][ rand() & 3 ] ); } } break; case EV_FOOTSTEP_SQUELCH: if ( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE ) { trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_FLESH ][ rand() & 3 ] ); } break; case EV_FOOTSPLASH: if ( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE ) { trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_SPLASH ][ rand() & 3 ] ); } break; case EV_FOOTWADE: if ( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE ) { trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_SPLASH ][ rand() & 3 ] ); } break; case EV_SWIM: if ( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE ) { trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_SPLASH ][ rand() & 3 ] ); } break; case 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: // use a general pain sound trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100_1.wav" ) ); if ( clientNum == cg.predictedPlayerState.clientNum ) { // smooth landing z changes cg.landChange = -16; cg.landTime = cg.time; } break; case EV_FALL_FAR: trap_S_StartSound( NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) ); 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_FALLING: trap_S_StartSound( NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*falling1.wav" ) ); break; case EV_STEP_4: case EV_STEP_8: case EV_STEP_12: case EV_STEP_16: // smooth out step up transitions case EV_STEPDN_4: case EV_STEPDN_8: case EV_STEPDN_12: case EV_STEPDN_16: // smooth out step down transitions { 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 < steptime ) { oldStep = cg.stepChange * ( steptime - delta ) / steptime; } else { oldStep = 0; } // add this amount if ( event >= EV_STEPDN_4 ) { step = 4 * ( event - EV_STEPDN_4 + 1 ); cg.stepChange = oldStep - step; } else { step = 4 * ( event - EV_STEP_4 + 1 ); cg.stepChange = oldStep + step; } if ( cg.stepChange > MAX_STEP_CHANGE ) { cg.stepChange = MAX_STEP_CHANGE; } else if ( cg.stepChange < -MAX_STEP_CHANGE ) { cg.stepChange = -MAX_STEP_CHANGE; } cg.stepTime = cg.time; break; } case EV_JUMP: trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) ); if ( BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_CLASS ], SCA_WALLJUMPER ) ) { vec3_t surfNormal, refNormal = { 0.0f, 0.0f, 1.0f }; vec3_t rotAxis; if ( clientNum != cg.predictedPlayerState.clientNum ) { break; } //set surfNormal VectorCopy( cg.predictedPlayerState.grapplePoint, surfNormal ); //if we are moving from one surface to another smooth the transition if ( !VectorCompare( surfNormal, cg.lastNormal ) && surfNormal[ 2 ] != 1.0f ) { CrossProduct( refNormal, surfNormal, rotAxis ); VectorNormalize( rotAxis ); //add the op CG_addSmoothOp( rotAxis, 15.0f, 1.0f ); } //copy the current normal to the lastNormal VectorCopy( surfNormal, cg.lastNormal ); } break; case EV_LEV1_GRAB: trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL1Grab ); break; case EV_LEV4_TRAMPLE_PREPARE: trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL4ChargePrepare ); break; case EV_LEV4_TRAMPLE_START: //FIXME: stop cgs.media.alienL4ChargePrepare playing here trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL4ChargeStart ); break; case EV_TAUNT: if ( !cg_noTaunt.integer ) { trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.wav" ) ); } break; case EV_WATER_TOUCH: trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.watrInSound ); break; case EV_WATER_LEAVE: trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound ); break; case EV_WATER_UNDER: trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound ); break; case EV_WATER_CLEAR: trap_S_StartSound( NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.wav" ) ); break; case EV_JETPACK_ENABLE: // TODO: Trigger jetpack enable animation break; case EV_JETPACK_DISABLE: // TODO: Trigger jetpack disable animation break; case EV_JETPACK_START: // TODO: Start jetpack gfx/sfx break; case EV_JETPACK_STOP: // TODO: Stop jetpack gfx/sfx break; case EV_NOAMMO: trap_S_StartSound( NULL, es->number, CHAN_WEAPON, cgs.media.weaponEmptyClick ); break; case EV_CHANGE_WEAPON: trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.selectSound ); break; case EV_FIRE_WEAPON: CG_HandleFireWeapon( cent, WPM_PRIMARY ); break; case EV_FIRE_WEAPON2: CG_HandleFireWeapon( cent, WPM_SECONDARY ); break; case EV_FIRE_WEAPON3: CG_HandleFireWeapon( cent, WPM_TERTIARY ); break; case EV_WEAPON_RELOAD: if ( cg_weapons[ es->eventParm ].wim[ WPM_PRIMARY ].reloadSound ) { trap_S_StartSound( NULL, es->number, CHAN_WEAPON, cg_weapons[ es->eventParm ].wim[ WPM_PRIMARY ].reloadSound ); } break; case EV_PLAYER_TELEPORT_IN: //deprecated break; case EV_PLAYER_TELEPORT_OUT: CG_PlayerDisconnect( position ); break; case EV_BUILD_CONSTRUCT: break; case EV_BUILD_DESTROY: break; case EV_AMMO_REFILL: case EV_CLIPS_REFILL: case EV_FUEL_REFILL: // TODO: Add different sounds for EV_AMMO_REFILL, EV_CLIPS_REFILL, EV_FUEL_REFILL trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.repeaterUseSound ); break; case EV_GRENADE_BOUNCE: if ( rand() & 1 ) { trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.hardBounceSound1 ); } else { trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.hardBounceSound2 ); } break; case EV_WEAPON_HIT_ENTITY: CG_HandleWeaponHitEntity( es, position ); break; case EV_WEAPON_HIT_ENVIRONMENT: CG_HandleWeaponHitWall( es, position ); break; case EV_MISSILE_HIT_ENTITY: CG_HandleMissileHitEntity( es, position ); break; // currently there is no support for metal sounds case EV_MISSILE_HIT_ENVIRONMENT: case EV_MISSILE_HIT_METAL: CG_HandleMissileHitWall( es, position ); break; case EV_SHOTGUN: CG_HandleFireShotgun( es ); break; case EV_HUMAN_BUILDABLE_DYING: CG_HumanBuildableDying( (buildable_t) es->modelindex, position ); break; case EV_HUMAN_BUILDABLE_EXPLOSION: ByteToDir( es->eventParm, dir ); CG_HumanBuildableExplosion( (buildable_t) es->modelindex, position, dir ); break; case EV_ALIEN_BUILDABLE_EXPLOSION: ByteToDir( es->eventParm, dir ); CG_AlienBuildableExplosion( position, dir ); break; case EV_TESLATRAIL: cent->currentState.weapon = WP_TESLAGEN; { centity_t *source = &cg_entities[ es->generic1 ]; centity_t *target = &cg_entities[ es->clientNum ]; vec3_t sourceOffset = { 0.0f, 0.0f, 28.0f }; if ( !CG_IsTrailSystemValid( &source->muzzleTS ) ) { source->muzzleTS = CG_SpawnNewTrailSystem( cgs.media.teslaZapTS ); if ( CG_IsTrailSystemValid( &source->muzzleTS ) ) { CG_SetAttachmentCent( &source->muzzleTS->frontAttachment, source ); CG_SetAttachmentCent( &source->muzzleTS->backAttachment, target ); CG_AttachToCent( &source->muzzleTS->frontAttachment ); CG_AttachToCent( &source->muzzleTS->backAttachment ); CG_SetAttachmentOffset( &source->muzzleTS->frontAttachment, sourceOffset ); source->muzzleTSDeathTime = cg.time + cg_teslaTrailTime.integer; } } } break; case 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 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_PAIN: // local player sounds are triggered in CG_CheckLocalSounds, // so ignore events on the player if ( cent->currentState.number != cg.snap->ps.clientNum ) { CG_PainEvent( cent, es->eventParm ); } break; case EV_DEATH1: case EV_DEATH2: case EV_DEATH3: trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, va( "*death%i.wav", event - EV_DEATH1 + 1 ) ) ); break; case EV_OBITUARY: CG_Obituary( es ); break; case EV_GIB_PLAYER: // no gibbing break; case EV_STOPLOOPINGSOUND: trap_S_StopLoopingSound( es->number ); es->loopSound = 0; break; case EV_DEBUG_LINE: CG_Beam( cent ); break; case EV_BUILD_DELAY: if ( clientNum == cg.predictedPlayerState.clientNum ) { trap_S_StartLocalSound( cgs.media.buildableRepairedSound, CHAN_LOCAL_SOUND ); cg.lastBuildAttempt = cg.time; } break; case EV_BUILD_REPAIR: trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.buildableRepairSound ); break; case EV_BUILD_REPAIRED: trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.buildableRepairedSound ); break; case EV_OVERMIND_ATTACK_1: case EV_OVERMIND_ATTACK_2: if ( cg.predictedPlayerState.persistant[ PERS_TEAM ] == TEAM_ALIENS ) { trap_S_StartLocalSound( cgs.media.alienOvermindAttack, CHAN_ANNOUNCER ); CG_CenterPrint( va( "^%c%s", "31"[ event - EV_OVERMIND_ATTACK_1 ], _( "The Overmind is under attack!" ) ), 200, GIANTCHAR_WIDTH * 4 ); } break; case EV_OVERMIND_DYING: if ( cg.predictedPlayerState.persistant[ PERS_TEAM ] == TEAM_ALIENS ) { trap_S_StartLocalSound( cgs.media.alienOvermindDying, CHAN_ANNOUNCER ); CG_CenterPrint( _( "^1The Overmind is dying!" ), 200, GIANTCHAR_WIDTH * 4 ); } break; case EV_REACTOR_ATTACK_1: case EV_REACTOR_ATTACK_2: if ( cg.predictedPlayerState.persistant[ PERS_TEAM ] == TEAM_HUMANS ) { CG_CenterPrint( va( "^%c%s", "31"[ event - EV_REACTOR_ATTACK_1 ], _( "The reactor is under attack!" ) ), 200, GIANTCHAR_WIDTH * 4 ); } break; case EV_REACTOR_DYING: if ( cg.predictedPlayerState.persistant[ PERS_TEAM ] == TEAM_HUMANS ) { CG_CenterPrint( _( "^1The reactor is about to explode!" ), 200, GIANTCHAR_WIDTH * 4 ); } break; case EV_WARN_ATTACK: // if eventParm is non-zero, this is for humans and there's a nearby reactor or repeater, otherwise it's for aliens if ( es->eventParm >= MAX_CLIENTS && es->eventParm < MAX_GENTITIES ) { const char *location; qboolean base = cg_entities[ es->eventParm ].currentState.modelindex == BA_H_REACTOR; centity_t *locent = CG_GetLocation( cg_entities[ es->eventParm ].currentState.origin ); CG_CenterPrint( base ? _( "Our base is under attack!" ) : _( "A forward base is under attack!" ), 200, GIANTCHAR_WIDTH * 4 ); if ( locent ) { location = CG_ConfigString( CS_LOCATIONS + locent->currentState.generic1 ); } else { location = CG_ConfigString( CS_LOCATIONS ); } if ( location && *location ) { Com_Printf( _( "%s Under attack – %s\n" ), base ? "[reactor]" : "[repeater]", location ); } else { Com_Printf( _( "%s Under attack\n" ), base ? "[reactor]" : "[repeater]" ); } } else // this is for aliens, and the overmind is in range { CG_CenterPrint( _( "Our base is under attack!" ), 200, GIANTCHAR_WIDTH * 4 ); } break; case EV_MGTURRET_SPINUP: trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.turretSpinupSound ); break; case EV_OVERMIND_SPAWNS: if ( cg.predictedPlayerState.persistant[ PERS_TEAM ] == TEAM_ALIENS ) { trap_S_StartLocalSound( cgs.media.alienOvermindSpawns, CHAN_ANNOUNCER ); CG_CenterPrint( "The Overmind needs spawns!", 200, GIANTCHAR_WIDTH * 4 ); } break; case EV_ALIEN_EVOLVE: trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.alienEvolveSound ); { particleSystem_t *ps = CG_SpawnNewParticleSystem( cgs.media.alienEvolvePS ); if ( CG_IsParticleSystemValid( &ps ) ) { CG_SetAttachmentCent( &ps->attachment, cent ); CG_AttachToCent( &ps->attachment ); } } if ( es->number == cg.clientNum ) { CG_ResetPainBlend(); cg.spawnTime = cg.time; } break; case EV_ALIEN_EVOLVE_FAILED: if ( clientNum == cg.predictedPlayerState.clientNum ) { //FIXME: change to "negative" sound trap_S_StartLocalSound( cgs.media.buildableRepairedSound, CHAN_LOCAL_SOUND ); cg.lastEvolveAttempt = cg.time; } break; case EV_ALIEN_ACIDTUBE: { particleSystem_t *ps = CG_SpawnNewParticleSystem( cgs.media.alienAcidTubePS ); if ( CG_IsParticleSystemValid( &ps ) ) { CG_SetAttachmentCent( &ps->attachment, cent ); ByteToDir( es->eventParm, dir ); CG_SetParticleSystemNormal( ps, dir ); CG_AttachToCent( &ps->attachment ); } } break; case EV_MEDKIT_USED: trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.medkitUseSound ); break; case EV_PLAYER_RESPAWN: if ( es->number == cg.clientNum ) { cg.spawnTime = cg.time; } break; case EV_LEV2_ZAP: CG_Level2Zap( es ); break; case EV_HIT: cg.hitTime = cg.time; break; case EV_MOMENTUM: CG_Momentum( es ); break; default: CG_Error( "Unknown event: %i", event ); } }
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_CheckLocalSounds ================== */ void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops ) { int reward, delta; // don't play the sounds if the player just spawned if( ps->persistant[ PERS_SPECSTATE ] != ops->persistant[ PERS_SPECSTATE ] ) return; //hitsound delta = ps->persistant[PERS_HITS] - ops->persistant[PERS_HITS]; if (cg_hitsound.integer == 3) { if (delta > 165) //125 trap_S_StartLocalSound( cgs.media.hitSound[8], CHAN_LOCAL_SOUND ); else if (delta > 120) //100 trap_S_StartLocalSound( cgs.media.hitSound[7], CHAN_LOCAL_SOUND ); else if (delta > 85) //75 trap_S_StartLocalSound( cgs.media.hitSound[6], CHAN_LOCAL_SOUND ); else if (delta > 50) trap_S_StartLocalSound( cgs.media.hitSound[5], CHAN_LOCAL_SOUND ); else if (delta > 25) trap_S_StartLocalSound( cgs.media.hitSound[4], CHAN_LOCAL_SOUND ); else if (delta > 12) trap_S_StartLocalSound( cgs.media.hitSound[3], CHAN_LOCAL_SOUND ); else if (delta > 8) trap_S_StartLocalSound( cgs.media.hitSound[2], CHAN_LOCAL_SOUND ); else if (delta > 4) trap_S_StartLocalSound( cgs.media.hitSound[1], CHAN_LOCAL_SOUND ); else if (delta > 0) //0 = no events trap_S_StartLocalSound( cgs.media.hitSound[0], CHAN_LOCAL_SOUND ); } else if (cg_hitsound.integer == 2) { if (delta > 8) trap_S_StartLocalSound( cgs.media.hitSound[8], CHAN_LOCAL_SOUND ); else if (delta > 7) trap_S_StartLocalSound( cgs.media.hitSound[7], CHAN_LOCAL_SOUND ); else if (delta > 6) trap_S_StartLocalSound( cgs.media.hitSound[6], CHAN_LOCAL_SOUND ); else if (delta > 5) trap_S_StartLocalSound( cgs.media.hitSound[5], CHAN_LOCAL_SOUND ); else if (delta > 4) trap_S_StartLocalSound( cgs.media.hitSound[4], CHAN_LOCAL_SOUND ); else if (delta > 3) trap_S_StartLocalSound( cgs.media.hitSound[3], CHAN_LOCAL_SOUND ); else if (delta > 2) trap_S_StartLocalSound( cgs.media.hitSound[2], CHAN_LOCAL_SOUND ); else if (delta > 1) trap_S_StartLocalSound( cgs.media.hitSound[1], CHAN_LOCAL_SOUND ); else if (delta > 0) //0 = no events trap_S_StartLocalSound( cgs.media.hitSound[0], CHAN_LOCAL_SOUND ); } else if (cg_hitsound.integer && (delta > 0)) //no tonal change trap_S_StartLocalSound( cgs.media.hitSound[4], CHAN_LOCAL_SOUND ); //health changes of more than -1 should make pain sounds //and don't play hurt sound if evolving if( ps->stats[ STAT_HEALTH ] < ops->stats[ STAT_HEALTH ] - 1 && ps->stats[ STAT_CLASS ] == ops->stats[ STAT_CLASS ] ) { float healthlost = ((ops->stats[ STAT_HEALTH ] - ps->stats[ STAT_HEALTH ])/ps->stats[ STAT_MAX_HEALTH ]); if( ps->stats[ STAT_HEALTH ] > 0 ) { CG_PainEvent( &cg.predictedPlayerEntity, ps->stats[ STAT_HEALTH ] ); //play critical hit! sound if lost > 30% hp if (healthlost > 0.3) trap_S_StartLocalSound( cgs.media.hitSound[9], CHAN_LOCAL_SOUND ); } } //Don't spam it if the user is spamming spacebar up a stair (Urasai! Annoying!) if(cg_doublejumpsound.integer && ps->persistant[PERS_DOUBLEJUMPED] > ops->persistant[PERS_DOUBLEJUMPED]) { trap_S_StartLocalSound( cgs.media.doublejumpsound, CHAN_LOCAL_SOUND ); } // health changes of more than -1 should make pain sounds if( ps->stats[ STAT_HEALTH ] < ops->stats[ STAT_HEALTH ] - 1 ) { if( ps->stats[ STAT_HEALTH ] > 0 ) CG_PainEvent( &cg.predictedPlayerEntity, ps->stats[ STAT_HEALTH ] ); } if( ( BG_UpgradeIsActive( UP_JETPACK, ps->stats ) || ( cg.predictedPlayerEntity.jetPackJumpTime + 1000 > cg.time && cg.predictedPlayerEntity.jetPackJumpTime + 250 < cg.time ) ) && ps->stats[ STAT_FUEL ] <= JETPACK_FUEL_LOW ) { static int last = 0; if( last + 740 < cg.time ) { trap_S_StartSound( NULL, cg.predictedPlayerState.clientNum, CHAN_AUTO, cgs.media.jetpackLowFuelSound ); last = cg.time; } } // if we are going into the intermission, don't start any voices if( cg.intermissionStarted ) return; // reward sounds reward = qfalse; }
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 ][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 ); 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.wav" ) ); 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.wav" ) ); 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.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(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; #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_itemlist[ 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, 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_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_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 ( 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_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; 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; //unlagged - attack prediction #2 // if the client is us, unlagged is on server-side, and we've got it client-side if ( es->clientNum == cg.predictedPlayerState.clientNum && cgs.delagHitscan && (cg_delag.integer & 1 || cg_delag.integer & 16) ) { // do nothing, because it was already predicted //Com_Printf("Ignoring rail trail event\n"); } else { if(es->clientNum == cg.snap->ps.clientNum && !cg.renderingThirdPerson) { if(cg_drawGun.integer == 2) VectorMA(es->origin2, 8, cg.refdef.viewaxis[1], es->origin2); else if(cg_drawGun.integer == 3) VectorMA(es->origin2, 4, cg.refdef.viewaxis[1], es->origin2); } // draw a rail trail, because it wasn't predicted CG_RailTrail( ci, 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->clientNum, position, dir, IMPACTSOUND_DEFAULT ); } //Com_Printf("Non-predicted rail trail\n"); } //unlagged - attack prediction #2 break; case EV_BULLET_HIT_WALL: DEBUGNAME("EV_BULLET_HIT_WALL"); //unlagged - attack prediction #2 // if the client is us, unlagged is on server-side, and we've got it client-side if ( es->clientNum == cg.predictedPlayerState.clientNum && cgs.delagHitscan && (cg_delag.integer & 1 || cg_delag.integer & 2) ) { // do nothing, because it was already predicted //Com_Printf("Ignoring bullet event\n"); } else { // do the bullet, because it wasn't predicted ByteToDir( es->eventParm, dir ); CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD ); //Com_Printf("Non-predicted bullet\n"); } //unlagged - attack prediction #2 break; case EV_BULLET_HIT_FLESH: DEBUGNAME("EV_BULLET_HIT_FLESH"); //unlagged - attack prediction #2 // if the client is us, unlagged is on server-side, and we've got it client-side if ( es->clientNum == cg.predictedPlayerState.clientNum && cgs.delagHitscan && (cg_delag.integer & 1 || cg_delag.integer & 2) ) { // do nothing, because it was already predicted //Com_Printf("Ignoring bullet event\n"); } else { // do the bullet, because it wasn't predicted CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm ); //Com_Printf("Non-predicted bullet\n"); } //unlagged - attack prediction #2 break; case EV_SHOTGUN: DEBUGNAME("EV_SHOTGUN"); //unlagged - attack prediction #2 // if the client is us, unlagged is on server-side, and we've got it client-side if ( es->otherEntityNum == cg.predictedPlayerState.clientNum && cgs.delagHitscan && (cg_delag.integer & 1 || cg_delag.integer & 4) ) { // do nothing, because it was already predicted //Com_Printf("Ignoring shotgun event\n"); } else { // do the shotgun pattern, because it wasn't predicted CG_ShotgunFire( es ); //Com_Printf("Non-predicted shotgun pattern\n"); } //unlagged - attack prediction #2 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 if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED ) 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 ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE ) CG_AddBufferedSound( cgs.media.captureYourTeamSound ); else CG_AddBufferedSound( cgs.media.captureOpponentSound ); break; case GTS_RED_RETURN: // CTF: blue flag returned, 1FCTF: never used if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED ) 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 ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE ) 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 (cg.snap->ps.powerups[PW_BLUEFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) { } else { if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) { //#ifdef MISSIONPACK if (cgs.gametype == GT_1FCTF) CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound ); else //#endif CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound ); } else if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) { //#ifdef MISSIONPACK if (cgs.gametype == GT_1FCTF) CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound ); else //#endif CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound ); } } 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 (cg.snap->ps.powerups[PW_REDFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) { } else { if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) { //#ifdef MISSIONPACK if (cgs.gametype == GT_1FCTF) CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound ); else //#endif CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound ); } else if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) { //#ifdef MISSIONPACK if (cgs.gametype == GT_1FCTF) CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound ); else //#endif CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound ); } } break; case GTS_REDOBELISK_ATTACKED: // Overload: red obelisk is being attacked if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) { CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound ); } break; case GTS_BLUEOBELISK_ATTACKED: // Overload: blue obelisk is being attacked if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) { CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound ); } break; 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: CG_AddBufferedSound(cgs.media.redLeadsSound); break; case GTS_BLUETEAM_TOOK_LEAD: CG_AddBufferedSound(cgs.media.blueLeadsSound); break; case GTS_TEAMS_ARE_TIED: CG_AddBufferedSound( cgs.media.teamsTiedSound ); break; case GTS_KAMIKAZE: trap_S_StartLocalSound(cgs.media.kamikazeFarSound, CHAN_ANNOUNCER); 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"); 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_Obituary( es ); break; // // powerup events // case EV_POWERUP_QUAD: DEBUGNAME("EV_POWERUP_QUAD"); if ( es->number == cg.snap->ps.clientNum ) { cg.powerupActive = PW_QUAD; cg.powerupTime = cg.time; } trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.quadSound ); break; case EV_POWERUP_BATTLESUIT: DEBUGNAME("EV_POWERUP_BATTLESUIT"); if ( es->number == cg.snap->ps.clientNum ) { cg.powerupActive = PW_BATTLESUIT; cg.powerupTime = cg.time; } trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.protectSound ); break; case EV_POWERUP_REGEN: DEBUGNAME("EV_POWERUP_REGEN"); if ( es->number == cg.snap->ps.clientNum ) { cg.powerupActive = PW_REGEN; cg.powerupTime = cg.time; } trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.regenSound ); break; case EV_GIB_PLAYER: DEBUGNAME("EV_GIB_PLAYER"); // 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 ); } CG_GibPlayer( cent->lerpOrigin ); 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_RunBuildableLerpFrame Sets cg.snap, cg.oldFrame, and cg.backlerp cg.time should be between oldFrameTime and frameTime after exit =============== */ static void CG_RunBuildableLerpFrame( centity_t *cent ) { int f, numFrames; buildable_t buildable = cent->currentState.modelindex; lerpFrame_t *lf = ¢->lerpFrame; animation_t *anim; buildableAnimNumber_t newAnimation = cent->buildableAnim & ~( ANIM_TOGGLEBIT|ANIM_FORCEBIT ); // debugging tool to get no animations if( cg_animSpeed.integer == 0 ) { lf->oldFrame = lf->frame = lf->backlerp = 0; return; } // see if the animation sequence is switching if( newAnimation != lf->animationNumber || !lf->animation ) { if( cg_debugRandom.integer ) CG_Printf( "newAnimation: %d lf->animationNumber: %d lf->animation: %d\n", newAnimation, lf->animationNumber, lf->animation ); CG_SetBuildableLerpFrameAnimation( buildable, lf, newAnimation ); if( !cg_buildables[ buildable ].sounds[ newAnimation ].looped && cg_buildables[ buildable ].sounds[ newAnimation ].enabled ) { if( cg_debugRandom.integer ) CG_Printf( "Sound for animation %d for a %s\n", newAnimation, BG_FindHumanNameForBuildable( buildable ) ); trap_S_StartSound( cent->lerpOrigin, cent->currentState.number, CHAN_AUTO, cg_buildables[ buildable ].sounds[ newAnimation ].sound ); } } if( cg_buildables[ buildable ].sounds[ lf->animationNumber ].looped && cg_buildables[ buildable ].sounds[ lf->animationNumber ].enabled ) trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cg_buildables[ buildable ].sounds[ lf->animationNumber ].sound ); // if we have passed the current frame, move it to // oldFrame and calculate a new frame if( cg.time >= lf->frameTime ) { lf->oldFrame = lf->frame; lf->oldFrameTime = lf->frameTime; // get the next frame based on the animation anim = lf->animation; if( !anim->frameLerp ) return; // shouldn't happen if ( cg.time < lf->animationTime ) lf->frameTime = lf->animationTime; // initial lerp else lf->frameTime = lf->oldFrameTime + anim->frameLerp; f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp; numFrames = anim->numFrames; if(anim->flipflop) numFrames *= 2; if( f >= numFrames ) { f -= numFrames; if( anim->loopFrames ) { f %= anim->loopFrames; f += anim->numFrames - anim->loopFrames; } else { f = numFrames - 1; // the animation is stuck at the end, so it // can immediately transition to another sequence lf->frameTime = cg.time; cent->buildableAnim = cent->currentState.torsoAnim; } } if( anim->reversed ) lf->frame = anim->firstFrame + anim->numFrames - 1 - f; else if( anim->flipflop && f >= anim->numFrames ) lf->frame = anim->firstFrame + anim->numFrames - 1 - ( f % anim->numFrames ); else lf->frame = anim->firstFrame + f; if( cg.time > lf->frameTime ) { lf->frameTime = cg.time; if( cg_debugAnim.integer ) CG_Printf( "Clamp lf->frameTime\n"); } } if( lf->frameTime > cg.time + 200 ) lf->frameTime = cg.time; if( lf->oldFrameTime > cg.time ) lf->oldFrameTime = cg.time; // calculate current lerp value if( lf->frameTime == lf->oldFrameTime ) lf->backlerp = 0; else lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime ); }
/* ================== CG_Buildable ================== */ void CG_Buildable( centity_t *cent ) { refEntity_t ent; entityState_t *es = ¢->currentState; vec3_t angles; vec3_t surfNormal, xNormal, mins, maxs; vec3_t refNormal = { 0.0f, 0.0f, 1.0f }; float rotAngle; buildableTeam_t team = BG_FindTeamForBuildable( es->modelindex ); float scale; int health; float healthScale; //must be before EF_NODRAW check if( team == BIT_ALIENS ) CG_Creep( cent ); // if set to invisible, skip if( es->eFlags & EF_NODRAW ) { if( CG_IsParticleSystemValid( ¢->buildablePS ) ) CG_DestroyParticleSystem( ¢->buildablePS ); return; } memset ( &ent, 0, sizeof( ent ) ); VectorCopy( cent->lerpOrigin, ent.origin ); VectorCopy( cent->lerpOrigin, ent.oldorigin ); VectorCopy( cent->lerpOrigin, ent.lightingOrigin ); VectorCopy( es->origin2, surfNormal ); VectorCopy( es->angles, angles ); BG_FindBBoxForBuildable( es->modelindex, mins, maxs ); if( es->pos.trType == TR_STATIONARY ) CG_PositionAndOrientateBuildable( angles, ent.origin, surfNormal, es->number, mins, maxs, ent.axis, ent.origin ); //offset on the Z axis if required VectorMA( ent.origin, BG_FindZOffsetForBuildable( es->modelindex ), surfNormal, ent.origin ); VectorCopy( ent.origin, ent.oldorigin ); // don't positionally lerp at all VectorCopy( ent.origin, ent.lightingOrigin ); ent.hModel = cg_buildables[ es->modelindex ].models[ 0 ]; if( !( es->generic1 & B_SPAWNED_TOGGLEBIT ) ) { sfxHandle_t prebuildSound = cgs.media.humanBuildablePrebuild; if( team == BIT_HUMANS ) { ent.customShader = cgs.media.humanSpawningShader; prebuildSound = cgs.media.humanBuildablePrebuild; } else if( team == BIT_ALIENS ) prebuildSound = cgs.media.alienBuildablePrebuild; trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, prebuildSound ); } CG_BuildableAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp ); //rescale the model scale = BG_FindModelScaleForBuildable( es->modelindex ); if( scale != 1.0f ) { VectorScale( ent.axis[ 0 ], scale, ent.axis[ 0 ] ); VectorScale( ent.axis[ 1 ], scale, ent.axis[ 1 ] ); VectorScale( ent.axis[ 2 ], scale, ent.axis[ 2 ] ); ent.nonNormalizedAxes = qtrue; } else ent.nonNormalizedAxes = qfalse; //add to refresh list trap_R_AddRefEntityToScene( &ent ); CrossProduct( surfNormal, refNormal, xNormal ); VectorNormalize( xNormal ); rotAngle = RAD2DEG( acos( DotProduct( surfNormal, refNormal ) ) ); //turret barrel bit if( cg_buildables[ es->modelindex ].models[ 1 ] ) { refEntity_t turretBarrel; vec3_t flatAxis[ 3 ]; memset( &turretBarrel, 0, sizeof( turretBarrel ) ); turretBarrel.hModel = cg_buildables[ es->modelindex ].models[ 1 ]; CG_PositionEntityOnTag( &turretBarrel, &ent, ent.hModel, "tag_turret" ); VectorCopy( cent->lerpOrigin, turretBarrel.lightingOrigin ); AnglesToAxis( es->angles2, flatAxis ); RotatePointAroundVector( turretBarrel.axis[ 0 ], xNormal, flatAxis[ 0 ], -rotAngle ); RotatePointAroundVector( turretBarrel.axis[ 1 ], xNormal, flatAxis[ 1 ], -rotAngle ); RotatePointAroundVector( turretBarrel.axis[ 2 ], xNormal, flatAxis[ 2 ], -rotAngle ); turretBarrel.oldframe = ent.oldframe; turretBarrel.frame = ent.frame; turretBarrel.backlerp = ent.backlerp; turretBarrel.customShader = ent.customShader; if( scale != 1.0f ) { VectorScale( turretBarrel.axis[ 0 ], scale, turretBarrel.axis[ 0 ] ); VectorScale( turretBarrel.axis[ 1 ], scale, turretBarrel.axis[ 1 ] ); VectorScale( turretBarrel.axis[ 2 ], scale, turretBarrel.axis[ 2 ] ); turretBarrel.nonNormalizedAxes = qtrue; } else turretBarrel.nonNormalizedAxes = qfalse; trap_R_AddRefEntityToScene( &turretBarrel ); } //turret barrel bit if( cg_buildables[ es->modelindex ].models[ 2 ] ) { refEntity_t turretTop; vec3_t flatAxis[ 3 ]; vec3_t swivelAngles; memset( &turretTop, 0, sizeof( turretTop ) ); VectorCopy( es->angles2, swivelAngles ); swivelAngles[ PITCH ] = 0.0f; turretTop.hModel = cg_buildables[ es->modelindex ].models[ 2 ]; CG_PositionRotatedEntityOnTag( &turretTop, &ent, ent.hModel, "tag_turret" ); VectorCopy( cent->lerpOrigin, turretTop.lightingOrigin ); AnglesToAxis( swivelAngles, flatAxis ); RotatePointAroundVector( turretTop.axis[ 0 ], xNormal, flatAxis[ 0 ], -rotAngle ); RotatePointAroundVector( turretTop.axis[ 1 ], xNormal, flatAxis[ 1 ], -rotAngle ); RotatePointAroundVector( turretTop.axis[ 2 ], xNormal, flatAxis[ 2 ], -rotAngle ); turretTop.oldframe = ent.oldframe; turretTop.frame = ent.frame; turretTop.backlerp = ent.backlerp; turretTop.customShader = ent.customShader; if( scale != 1.0f ) { VectorScale( turretTop.axis[ 0 ], scale, turretTop.axis[ 0 ] ); VectorScale( turretTop.axis[ 1 ], scale, turretTop.axis[ 1 ] ); VectorScale( turretTop.axis[ 2 ], scale, turretTop.axis[ 2 ] ); turretTop.nonNormalizedAxes = qtrue; } else turretTop.nonNormalizedAxes = qfalse; trap_R_AddRefEntityToScene( &turretTop ); } //weapon effects for turrets if( es->eFlags & EF_FIRING ) { weaponInfo_t *weapon = &cg_weapons[ es->weapon ]; if( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME || BG_FindProjTypeForBuildable( es->modelindex ) == WP_TESLAGEN ) { if( weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 0 ] || weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 1 ] || weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 2 ] ) { trap_R_AddLightToScene( cent->lerpOrigin, 300 + ( rand( ) & 31 ), weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 0 ], weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 1 ], weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 2 ] ); } } if( weapon->wim[ WPM_PRIMARY ].firingSound ) { trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, weapon->wim[ WPM_PRIMARY ].firingSound ); } else if( weapon->readySound ) trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, weapon->readySound ); } health = es->generic1 & B_HEALTH_MASK; healthScale = (float)health / B_HEALTH_MASK; if( healthScale < cent->lastBuildableHealthScale && ( es->generic1 & B_SPAWNED_TOGGLEBIT ) ) { if( cent->lastBuildableDamageSoundTime + BUILDABLE_SOUND_PERIOD < cg.time ) { if( team == BIT_HUMANS ) { int i = rand( ) % 4; trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.humanBuildableDamage[ i ] ); } else if( team == BIT_ALIENS ) trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.alienBuildableDamage ); cent->lastBuildableDamageSoundTime = cg.time; } } cent->lastBuildableHealthScale = healthScale; //smoke etc for damaged buildables CG_BuildableParticleEffects( cent ); }