/* * CG_FlyParticles */ static void CG_FlyParticles( const vec3_t origin, int count ) { int i, j; float angle, sp, sy, cp, cy; vec3_t forward, dir; float dist, ltime; cparticle_t *p; if( !cg_particles->integer ) { return; } if( count > NUMVERTEXNORMALS ) { count = NUMVERTEXNORMALS; } if( !avelocities[0][0] ) { for( i = 0; i < NUMVERTEXNORMALS; i++ ) for( j = 0; j < 3; j++ ) avelocities[i][j] = ( rand() & 255 ) * 0.01; } i = 0; ltime = (float)cg.time / 1000.0; count /= 2; if( cg_numparticles + count > MAX_PARTICLES ) { count = MAX_PARTICLES - cg_numparticles; } for( p = &particles[cg_numparticles], cg_numparticles += count; count > 0; count--, p++ ) { CG_InitParticle( p, 1, 1, 0, 0, 0, NULL ); angle = ltime * avelocities[i][0]; sy = sin( angle ); cy = cos( angle ); angle = ltime * avelocities[i][1]; sp = sin( angle ); cp = cos( angle ); forward[0] = cp * cy; forward[1] = cp * sy; forward[2] = -sp; dist = sin( ltime + i ) * 64; ByteToDir( i, dir ); p->org[0] = origin[0] + dir[0] * dist + forward[0] * BEAMLENGTH; p->org[1] = origin[1] + dir[1] * dist + forward[1] * BEAMLENGTH; p->org[2] = origin[2] + dir[2] * dist + forward[2] * BEAMLENGTH; VectorClear( p->vel ); VectorClear( p->accel ); p->alphavel = -100; i += 2; } }
void locateCamera(gentity_t *ent) { vec3_t dir; gentity_t *target; gentity_t *owner; owner = G_PickTarget(ent->target); if (!owner) { G_Printf("Couldn't find target for misc_portal_surface\n"); G_FreeEntity(ent); return; } ent->r.ownerNum = owner->s.number; // frame holds the rotate speed if (owner->spawnflags & 1) ent->s.frame = 25; else if (owner->spawnflags & 2) ent->s.frame = 75; // swing camera ? if (owner->spawnflags & 4) { // set to 0 for no rotation at all ent->s.misc = 0; } else ent->s.misc = 1; // clientNum holds the rotate offset ent->s.clientNum = owner->s.clientNum; VectorCopy(owner->r.currentOrigin, ent->s.origin2); // see if the portal_camera has a target target = G_PickTarget(owner->target); if (target) { VectorSubtract(target->r.currentOrigin, owner->r.currentOrigin, dir); VectorNormalize(dir); } else G_SetMovedir(owner->r.currentAngles, dir); ent->s.eventParm = DirToByte(dir); ByteToDir(ent->s.eventParm, dir); vectoangles(dir, ent->r.currentAngles); ent->r.currentAngles[2] = ent->s.clientNum * 360.0f / 256; }
int qlua_getbytedir(lua_State *L) { centity_t *luaentity; vec3_t dir; luaL_checktype(L,1,LUA_TUSERDATA); luaentity = lua_toentity(L,1); if(luaentity != NULL) { ByteToDir( luaentity->currentState.eventParm, dir ); lua_pushvector(L,dir); return 1; } return 0; }
qboolean CG_VehicleWeaponImpact( centity_t *cent ) { // see if this is a missile entity that's owned by a vehicle and should do a special, overridden impact effect if ( (cent->currentState.eFlags & EF_JETPACK_ACTIVE) //hack so we know we're a vehicle Weapon shot && cent->currentState.otherEntityNum2 && g_vehWeaponInfo[cent->currentState.otherEntityNum2].iImpactFX ) { // missile is from a special vehWeapon vector3 normal; ByteToDir( cent->currentState.eventParm, &normal ); trap->FX_PlayEffectID( g_vehWeaponInfo[cent->currentState.otherEntityNum2].iImpactFX, ¢->lerpOrigin, &normal, -1, -1, qfalse ); return qtrue; } return qfalse; }
/* * CG_Event_WallJump */ void CG_Event_WallJump( entity_state_t *state, int parm, int ev ) { vec3_t normal, forward, right; ByteToDir( parm, normal ); AngleVectors( tv( state->angles[0], state->angles[1], 0 ), forward, right, NULL ); if( DotProduct( normal, right ) > 0.3 ) CG_PModel_AddAnimation( state->number, LEGS_WALLJUMP_RIGHT, 0, 0, EVENT_CHANNEL ); else if( -DotProduct( normal, right ) > 0.3 ) CG_PModel_AddAnimation( state->number, LEGS_WALLJUMP_LEFT, 0, 0, EVENT_CHANNEL ); else if( -DotProduct( normal, forward ) > 0.3 ) CG_PModel_AddAnimation( state->number, LEGS_WALLJUMP_BACK, 0, 0, EVENT_CHANNEL ); else CG_PModel_AddAnimation( state->number, LEGS_WALLJUMP, 0, 0, EVENT_CHANNEL ); if( ev == EV_WALLJUMP_FAILED ) { if( ISVIEWERENTITY( state->number ) ) trap_S_StartGlobalSound( CG_MediaSfx( cgs.media.sfxWalljumpFailed ), CHAN_BODY, cg_volume_effects->value ); else trap_S_StartRelativeSound( CG_MediaSfx( cgs.media.sfxWalljumpFailed ), state->number, CHAN_BODY, cg_volume_effects->value, ATTN_NORM ); } else { CG_SexedSound( state->number, CHAN_BODY, va( S_PLAYER_WALLJUMP_1_to_2, ( rand()&1 )+1 ), cg_volume_players->value ); // smoke effect if( cg_cartoonEffects->integer & 1 ) { vec3_t pos; VectorCopy( state->origin, pos ); pos[2] += 15; CG_DustCircle( pos, normal, 65, 12 ); } } //racesow - lm: filter out other players if( ISVIEWERENTITY( state->number )) CG_AddJumpspeed(); //!racesow }
/* ============== 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 G_MissileImpact( gentity_t *ent, trace_t *trace ) { #else void G_MissileImpact( gentity_t *ent, trace_t *trace, int shaderNum ) { #endif gentity_t *other; qboolean hitClient = qfalse; #ifndef SMOKINGUNS #ifdef MISSIONPACK vec3_t forward, impactpoint, bouncedir; int eFlags; #endif #else qboolean hitKnife = qfalse; vec3_t bottledirs[ALC_COUNT]; #endif other = &g_entities[trace->entityNum]; #ifndef SMOKINGUNS // check for bounce if ( !other->takedamage && ( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) ) { G_BounceMissile( ent, trace ); G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 ); return; } #ifdef MISSIONPACK if ( other->takedamage ) { if ( ent->s.weapon != WP_PROX_LAUNCHER ) { if ( other->client && other->client->invulnerabilityTime > level.time ) { // VectorCopy( ent->s.pos.trDelta, forward ); VectorNormalize( forward ); if (G_InvulnerabilityEffect( other, forward, ent->s.pos.trBase, impactpoint, bouncedir )) { VectorCopy( bouncedir, trace->plane.normal ); eFlags = ent->s.eFlags & EF_BOUNCE_HALF; ent->s.eFlags &= ~EF_BOUNCE_HALF; G_BounceMissile( ent, trace ); ent->s.eFlags |= eFlags; } ent->target_ent = other; return; } } } #endif // impact damage if (other->takedamage) { #else if(other->takedamage) hitKnife = qtrue; // check for bounce if ( ( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) ) { G_BounceMissile( ent, trace ); return; } if (other->takedamage && ent->s.weapon != WP_DYNAMITE) { #endif // FIXME: wrong damage direction? if ( ent->damage ) { vec3_t velocity; if( LogAccuracyHit( other, &g_entities[ent->r.ownerNum] ) ) { g_entities[ent->r.ownerNum].client->accuracy_hits++; hitClient = qtrue; } BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity ); if ( VectorLength( velocity ) == 0 ) { velocity[2] = 1; // stepped on a grenade } #ifndef SMOKINGUNS G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity, ent->s.origin, ent->damage, 0, ent->methodOfDeath); #else // you can't make dynamite exploding by using a knife if(!(ent->s.weapon == WP_KNIFE && other->s.weapon == WP_DYNAMITE && other->s.eType == ET_ITEM)){ // prepare breakable, if not already initialized if(!(other->flags & FL_BREAKABLE_INIT)) G_BreakablePrepare(other, shaderNum); G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity, ent->s.origin, ent->damage, 0, ent->methodOfDeath); } #endif } } #ifndef SMOKINGUNS if( ent->s.weapon == WP_PROX_LAUNCHER ) { if( ent->s.pos.trType != TR_GRAVITY ) { return; } // if it's a player, stick it on to them (flag them and remove this entity) if( other->s.eType == ET_PLAYER && other->health > 0 ) { ProximityMine_Player( ent, other ); return; } SnapVectorTowards( trace->endpos, ent->s.pos.trBase ); G_SetOrigin( ent, trace->endpos ); ent->s.pos.trType = TR_STATIONARY; VectorClear( ent->s.pos.trDelta ); G_AddEvent( ent, EV_PROXIMITY_MINE_STICK, trace->surfaceFlags ); ent->think = ProximityMine_Activate; ent->nextthink = level.time + 2000; vectoangles( trace->plane.normal, ent->s.angles ); ent->s.angles[0] += 90; // link the prox mine to the other entity ent->enemy = other; ent->die = ProximityMine_Die; VectorCopy(trace->plane.normal, ent->movedir); VectorSet(ent->r.mins, -4, -4, -4); VectorSet(ent->r.maxs, 4, 4, 4); trap_LinkEntity(ent); return; } if (!strcmp(ent->classname, "hook")) { gentity_t *nent; vec3_t v; nent = G_Spawn(); if ( other->takedamage && other->client ) { G_AddEvent( nent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) ); nent->s.otherEntityNum = other->s.number; ent->enemy = other; v[0] = other->r.currentOrigin[0] + (other->r.mins[0] + other->r.maxs[0]) * 0.5; v[1] = other->r.currentOrigin[1] + (other->r.mins[1] + other->r.maxs[1]) * 0.5; v[2] = other->r.currentOrigin[2] + (other->r.mins[2] + other->r.maxs[2]) * 0.5; SnapVectorTowards( v, ent->s.pos.trBase ); // save net bandwidth } else { VectorCopy(trace->endpos, v); G_AddEvent( nent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) ); ent->enemy = NULL; } SnapVectorTowards( v, ent->s.pos.trBase ); // save net bandwidth nent->freeAfterEvent = qtrue; // change over to a normal entity right at the point of impact nent->s.eType = ET_GENERAL; ent->s.eType = ET_GRAPPLE; G_SetOrigin( ent, v ); G_SetOrigin( nent, v ); ent->think = Weapon_HookThink; ent->nextthink = level.time + FRAMETIME; ent->parent->client->ps.pm_flags |= PMF_GRAPPLE_PULL; VectorCopy( ent->r.currentOrigin, ent->parent->client->ps.grapplePoint); trap_LinkEntity( ent ); trap_LinkEntity( nent ); return; } #endif // is it cheaper in bandwidth to just remove this ent and create a new // one, rather than changing the missile into the explosion? #ifndef SMOKINGUNS if ( other->takedamage && other->client ) { #else // alcoohol impact if( !Q_stricmp(ent->classname, "alcohol")){ // no event //G_AddEvent( ent, EV_MISSILE_ALCOHOL, DirToByte( trace->plane.normal)); } else if( !Q_stricmp(ent->classname, "molotov")){ // we have to launch the whiskey drops int i; // set the directions for(i = 0; i < ALC_COUNT; i++){ int temp; VectorSet(bottledirs[i], (rand()%10)-5, (rand()%10)-5, (rand()%10)-3); // direction has to be exactly the same (client and server) temp = DirToByte(bottledirs[i]); ByteToDir(temp, bottledirs[i]); } // dirs BG_DirsToEntityState(&ent->s, bottledirs); // burning if(ent->s.apos.trDelta[0]) G_AddEvent( ent, EV_MISSILE_FIRE, DirToByte( trace->plane.normal)); // not burning else G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal)); } else if ( other->takedamage && other->client ) { #endif G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) ); ent->s.otherEntityNum = other->s.number; #ifndef SMOKINGUNS } else if( trace->surfaceFlags & SURF_METALSTEPS ) { #else } else if( trace->surfaceFlags & SURF_METAL ) { #endif G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) ); } else { G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) ); } #ifndef SMOKINGUNS ent->freeAfterEvent = qtrue; // change over to a normal entity right at the point of impact ent->s.eType = ET_GENERAL; #else if(Q_stricmp(ent->classname, "knife")){ ent->freeAfterEvent = qtrue; // change over to a normal entity right at the point of impact ent->s.eType = ET_GENERAL; } else { vec3_t dir; gitem_t *item; item = BG_FindItemForWeapon(WP_KNIFE); ent->s.modelindex = item-bg_itemlist; ent->s.modelindex2 = 1; ent->item = item; ent->s.eType = ET_ITEM; ent->s.pos.trType = TR_GRAVITY; ent->physicsBounce = 0.01f; ent->r.contents = CONTENTS_TRIGGER; ent->touch = Touch_Item; ent->nextthink = level.time + 100; ent->think = G_KnifeThink; ent->wait = level.time + 30000; ent->flags |= FL_THROWN_ITEM; vectoangles(ent->s.pos.trDelta, dir); VectorCopy(dir, ent->s.apos.trBase); VectorCopy(dir, ent->r.currentAngles); } //modified by Spoon END #endif SnapVectorTowards( trace->endpos, ent->s.pos.trBase ); // save net bandwidth G_SetOrigin( ent, trace->endpos ); // splash damage (doesn't apply to person directly hit) if ( ent->splashDamage ) { if( G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius, other, ent->splashMethodOfDeath ) ) { if( !hitClient ) { g_entities[ent->r.ownerNum].client->accuracy_hits++; } } } // spawn alcohol missiles #ifdef SMOKINGUNS if(!Q_stricmp(ent->classname, "molotov")){ BottleBreak( ent, trace->endpos, trace->plane.normal, bottledirs); } #endif trap_LinkEntity( ent ); } /* ================ G_RunMissile ================ */ void G_RunMissile( gentity_t *ent ) { vec3_t origin; trace_t tr; int passent; #ifdef SMOKINGUNS int shaderNum; gentity_t *traceEnt; #endif // get current position BG_EvaluateTrajectory( &ent->s.pos, level.time, origin ); // if this missile bounced off an invulnerability sphere if ( ent->target_ent ) { passent = ent->target_ent->s.number; } #ifndef SMOKINGUNS // prox mines that left the owner bbox will attach to anything, even the owner else if (ent->s.weapon == WP_PROX_LAUNCHER && ent->count) { passent = ENTITYNUM_NONE; } #endif else { // ignore interactions with the missile owner passent = ent->r.ownerNum; } // trace a line from the previous position to the current position #ifndef SMOKINGUNS trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask ); #else shaderNum = trap_Trace_New2( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask ); traceEnt = &g_entities[tr.entityNum]; #endif if ( tr.startsolid || tr.allsolid ) { // make sure the tr.entityNum is set to the entity we're stuck in #ifndef SMOKINGUNS trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask ); #else trap_Trace_New( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask ); #endif tr.fraction = 0; } else { VectorCopy( tr.endpos, ent->r.currentOrigin ); } trap_LinkEntity( ent ); if ( tr.fraction != 1 ) { #ifdef SMOKINGUNS VectorCopy(origin, ent->s.origin2); #endif // never explode or bounce on sky if ( tr.surfaceFlags & SURF_NOIMPACT ) { // If grapple, reset owner if (ent->parent && ent->parent->client && ent->parent->client->hook == ent) { ent->parent->client->hook = NULL; } // if its a dynamite or molotov let it move 10 seconds before deleting it #ifdef SMOKINGUNS if(ent->s.weapon == WP_DYNAMITE || ent->s.weapon == WP_MOLOTOV || ent->s.weapon == WP_KNIFE){ if(ent->mappart >= level.time && ent->mappart){ goto think; } else if(ent->mappart){ ent->mappart = 0; } else { ent->mappart = level.time + 5000; goto think; } } #endif G_FreeEntity( ent ); return; } #ifndef SMOKINGUNS G_MissileImpact( ent, &tr ); if ( ent->s.eType != ET_MISSILE ) { #else G_MissileImpact( ent, &tr, shaderNum ); if ( ent->s.eType != ET_MISSILE && ent->s.eType != ET_ITEM) { #endif return; // exploded } } #ifndef SMOKINGUNS // if the prox mine wasn't yet outside the player body if (ent->s.weapon == WP_PROX_LAUNCHER && !ent->count) { // check if the prox mine is outside the owner bbox trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, ENTITYNUM_NONE, ent->clipmask ); if (!tr.startsolid || tr.entityNum != ent->r.ownerNum) { ent->count = 1; } } #endif think: // check think function after bouncing G_RunThink( ent ); } //============================================================================= #ifndef SMOKINGUNS /* ================= fire_plasma ================= */ gentity_t *fire_plasma (gentity_t *self, vec3_t start, vec3_t dir) { gentity_t *bolt; VectorNormalize (dir); bolt = G_Spawn(); bolt->classname = "plasma"; bolt->nextthink = level.time + 10000; bolt->think = G_ExplodeMissile; bolt->s.eType = ET_MISSILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; bolt->s.weapon = WP_PLASMAGUN; bolt->r.ownerNum = self->s.number; bolt->parent = self; bolt->damage = 20; bolt->splashDamage = 15; bolt->splashRadius = 20; bolt->methodOfDeath = MOD_PLASMA; bolt->splashMethodOfDeath = MOD_PLASMA_SPLASH; bolt->clipmask = MASK_SHOT; bolt->target_ent = NULL; bolt->s.pos.trType = TR_LINEAR; bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame VectorCopy( start, bolt->s.pos.trBase ); VectorScale( dir, 2000, bolt->s.pos.trDelta ); SnapVector( bolt->s.pos.trDelta ); // save net bandwidth VectorCopy (start, bolt->r.currentOrigin); return bolt; } //============================================================================= /* ================= fire_grenade ================= */ gentity_t *fire_grenade (gentity_t *self, vec3_t start, vec3_t dir) { gentity_t *bolt; VectorNormalize (dir); bolt = G_Spawn(); bolt->classname = "grenade"; bolt->nextthink = level.time + 2500; bolt->think = G_ExplodeMissile; bolt->s.eType = ET_MISSILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; bolt->s.weapon = WP_GRENADE_LAUNCHER; bolt->s.eFlags = EF_BOUNCE_HALF; bolt->r.ownerNum = self->s.number; bolt->parent = self; bolt->damage = 100; bolt->splashDamage = 100; bolt->splashRadius = 150; bolt->methodOfDeath = MOD_GRENADE; bolt->splashMethodOfDeath = MOD_GRENADE_SPLASH; bolt->clipmask = MASK_SHOT; bolt->target_ent = NULL; bolt->s.pos.trType = TR_GRAVITY; bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame VectorCopy( start, bolt->s.pos.trBase ); VectorScale( dir, 700, bolt->s.pos.trDelta ); SnapVector( bolt->s.pos.trDelta ); // save net bandwidth VectorCopy (start, bolt->r.currentOrigin); return bolt; }
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_WATER_TOUCH: DEBUGNAME("EV_WATER_TOUCH"); S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrInSound ); break; case EV_WATER_LEAVE: DEBUGNAME("EV_WATER_LEAVE"); S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound ); break; case EV_WATER_UNDER: DEBUGNAME("EV_WATER_UNDER"); S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound ); break; case EV_WATER_CLEAR: DEBUGNAME("EV_WATER_CLEAR"); 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_TEAM) { S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.n_healthSound ); } else { S_StartSound (NULL, es->number, CHAN_AUTO, S_RegisterSound( item->pickup_sound, false ) ); } // 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 ) { S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, S_RegisterSound( item->pickup_sound, false ) ); } // show icon and name on status bar if ( es->number == cg.snap->ps.clientNum ) { CG_ItemPickup( index ); } } break; // // weapon events // case EV_FIRE_MG: DEBUGNAME("EV_FIRE_WEAPON"); CG_FireMachinegun( cent, false ); break; case EV_FIRE_WEAPON: DEBUGNAME("EV_FIRE_WEAPON"); CG_FireWeapon( cent ); break; case EV_FIRE_FLARE: DEBUGNAME("EV_FIRE_FLARE"); break; case EV_NUKE: DEBUGNAME("EV_NUKE"); CG_NukeEffect( cent, es ); break; case EV_FLAK: DEBUGNAME("EV_FLAK"); CG_FlakEffect( cent, es ); break; //================================================================= // // other events // case EV_ITEM_POP: DEBUGNAME("EV_ITEM_POP"); 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 S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound ); break; // // missile impacts // case EV_MISSILE_HIT: DEBUGNAME("EV_MISSILE_HIT"); ByteToDir( es->eventParm, dir ); CG_MissileHitWall( es->weaponIndex, 0, position, dir, IMPACTSOUND_DEFAULT ); break; case EV_MISSILE_MISS: DEBUGNAME("EV_MISSILE_MISS"); ByteToDir( es->eventParm, dir ); CG_MissileHitWall( es->weaponIndex, 0, position, dir, IMPACTSOUND_DEFAULT ); break; case EV_MISSILE_MISS_METAL: DEBUGNAME("EV_MISSILE_MISS_METAL"); ByteToDir( es->eventParm, dir ); CG_MissileHitWall( es->weaponIndex, 0, position, dir, IMPACTSOUND_METAL ); break; // MFQ3 events case EV_VEHICLE_HIT: DEBUGNAME("EV_VEHICLE_HIT"); CG_VehicleHit( position, es->eventParm ); break; case EV_VEHICLE_DIE: DEBUGNAME("EV_VEHICLE_DIE"); CG_GenericExplosion( position, EXPLODE_VEHICLE_DIE ); break; case EV_VEHICLE_GIB: DEBUGNAME("EV_VEHICLE_GIB"); if(availableVehicles[cgs.clientinfo[ cent->currentState.clientNum ].vehicle].cat & CAT_LQM) CG_GibPlayer(position); else CG_GenericExplosion( position, EXPLODE_VEHICLE_GIB ); break; case EV_BUILDING_EXPLODE: DEBUGNAME("EV_BUILDING_EXPLODE"); CG_GenericExplosion( position, EXPLODE_BUILDING ); break; case EV_GEAR_UP_FULL: DEBUGNAME("EV_GEAR_UP_FULL"); cent->gearAnimStartTime = 0; cent->gearAnim = GEAR_ANIM_STOP; cent->gearAnimFrame = GEAR_UP; break; case EV_GEAR_UP: DEBUGNAME("EV_GEAR_UP"); cent->gearAnimStartTime = cg.time; cent->gearAnim = GEAR_ANIM_UP; break; case EV_GEAR_STOP: DEBUGNAME("EV_GEAR_STOP"); cent->gearAnimStartTime = 0; cent->gearAnim = GEAR_ANIM_STOP; break; case EV_GEAR_DOWN: DEBUGNAME("EV_GEAR_DOWN"); cent->gearAnimStartTime = cg.time; cent->gearAnim = GEAR_ANIM_DOWN; break; case EV_GEAR_DOWN_FULL: DEBUGNAME("EV_GEAR_DOWN_FULL"); cent->gearAnimStartTime = 0; cent->gearAnim = GEAR_ANIM_STOP; { // old version /* if( cent->currentState.eType == ET_VEHICLE ) { clientInfo_t *ci; int clientNum; clientNum = cent->currentState.clientNum; if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) { Com_Error( ERR_DROP, "Bad clientNum on player entity (EV_GEAR_DOWN_FULL)"); } ci = &cgs.clientinfo[ clientNum ]; cent->gearAnimFrame = availableVehicles[ci->vehicle].maxGearFrame; } else if( cent->currentState.eType == ET_MISC_VEHICLE ) { cent->gearAnimFrame = availableVehicles[cent->currentState.modelindex].maxGearFrame; } */ // New version clientInfo_t *ci; int clientNum; clientNum = cent->currentState.clientNum; if( clientNum < 0 || clientNum >= MAX_CLIENTS ) { cent->gearAnimFrame = availableVehicles[cent->currentState.modelindex].maxGearFrame; } else { ci = &cgs.clientinfo[ clientNum ]; cent->gearAnimFrame = availableVehicles[ci->vehicle].maxGearFrame; } } break; case EV_BAY_UP_FULL: DEBUGNAME("EV_BAY_UP_FULL"); cent->bayAnimStartTime = 0; cent->bayAnim = BAY_ANIM_STOP; cent->bayAnimFrame = BAY_UP; break; case EV_BAY_UP: DEBUGNAME("EV_BAY_UP"); cent->bayAnimStartTime = cg.time; cent->bayAnim = BAY_ANIM_UP; break; case EV_BAY_STOP: DEBUGNAME("EV_BAY_STOP"); cent->bayAnimStartTime = 0; cent->bayAnim = BAY_ANIM_STOP; break; case EV_BAY_DOWN: DEBUGNAME("EV_BAY_DOWN"); cent->bayAnimStartTime = cg.time; cent->bayAnim = BAY_ANIM_DOWN; break; case EV_BAY_DOWN_FULL: DEBUGNAME("EV_BAY_DOWN_FULL"); cent->bayAnimStartTime = 0; cent->bayAnim = BAY_ANIM_STOP; break; case EV_GENERAL_SOUND: DEBUGNAME("EV_GENERAL_SOUND"); if ( cgs.gameSounds[ es->eventParm ] ) { S_StartSound (NULL, es->number, CHAN_VOICE, cgs.gameSounds[ es->eventParm ] ); } else { s = CG_ConfigString( CS_SOUNDS + es->eventParm ); 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 ] ) { S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] ); } else { s = CG_ConfigString( CS_SOUNDS + es->eventParm ); 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 == ClientBase::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 == ClientBase::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 == ClientBase::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 == ClientBase::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.objectives & OB_BLUEFLAG ) { } else { if (cgs.clientinfo[cg.clientNum].team == ClientBase::TEAM_BLUE) { CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound ); } else if (cgs.clientinfo[cg.clientNum].team == ClientBase::TEAM_RED) { 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.objectives & OB_REDFLAG ) { } else { if (cgs.clientinfo[cg.clientNum].team == ClientBase::TEAM_RED) { CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound ); } else if (cgs.clientinfo[cg.clientNum].team == ClientBase::TEAM_BLUE) { CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound ); } } 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; // MFQ3 case GTS_NUKE: S_StartLocalSound(cgs.media.nukeFarSound, 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"); 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_VehicleObituary( es ); break; case EV_DEBUG_LINE: DEBUGNAME("EV_DEBUG_LINE"); CG_Beam( cent ); break; default: DEBUGNAME("UNKNOWN"); Com_Error( ERR_DROP, "Unknown event: %i", event ); break; } }
/* * R_DrawPortalSurface * * Renders the portal view and captures the results from framebuffer if * we need to do a $portalmap stage. Note that for $portalmaps we must * use a different viewport. */ static void R_DrawPortalSurface( portalSurface_t *portalSurface ) { unsigned int i; int x, y, w, h; float dist, d, best_d; vec3_t viewerOrigin; vec3_t origin; mat3_t axis; entity_t *ent, *best; const entity_t *portal_ent = portalSurface->entity; cplane_t *portal_plane = &portalSurface->plane, *untransformed_plane = &portalSurface->untransformed_plane; const shader_t *shader = portalSurface->shader; vec_t *portal_mins = portalSurface->mins, *portal_maxs = portalSurface->maxs; vec_t *portal_centre = portalSurface->centre; qboolean mirror, refraction = qfalse; image_t *captureTexture; int captureTextureId = -1; int prevRenderFlags = 0; qboolean doReflection, doRefraction; image_t *portalTexures[2] = { NULL, NULL }; doReflection = doRefraction = qtrue; if( shader->flags & SHADER_PORTAL_CAPTURE ) { shaderpass_t *pass; captureTexture = NULL; captureTextureId = 0; for( i = 0, pass = shader->passes; i < shader->numpasses; i++, pass++ ) { if( pass->program_type == GLSL_PROGRAM_TYPE_DISTORTION ) { if( ( pass->alphagen.type == ALPHA_GEN_CONST && pass->alphagen.args[0] == 1 ) ) doRefraction = qfalse; else if( ( pass->alphagen.type == ALPHA_GEN_CONST && pass->alphagen.args[0] == 0 ) ) doReflection = qfalse; break; } } } else { captureTexture = NULL; captureTextureId = -1; } x = y = 0; w = rn.refdef.width; h = rn.refdef.height; dist = PlaneDiff( rn.viewOrigin, portal_plane ); if( dist <= BACKFACE_EPSILON || !doReflection ) { if( !( shader->flags & SHADER_PORTAL_CAPTURE2 ) || !doRefraction ) return; // even if we're behind the portal, we still need to capture // the second portal image for refraction refraction = qtrue; captureTexture = NULL; captureTextureId = 1; if( dist < 0 ) { VectorInverse( portal_plane->normal ); portal_plane->dist = -portal_plane->dist; } } if( !(rn.renderFlags & RF_NOVIS) && !R_ScissorForEntity( portal_ent, portal_mins, portal_maxs, &x, &y, &w, &h ) ) return; mirror = qtrue; // default to mirror view // it is stupid IMO that mirrors require a RT_PORTALSURFACE entity best = NULL; best_d = 100000000; for( i = 1; i < rsc.numEntities; i++ ) { ent = R_NUM2ENT(i); if( ent->rtype != RT_PORTALSURFACE ) continue; d = PlaneDiff( ent->origin, untransformed_plane ); if( ( d >= -64 ) && ( d <= 64 ) ) { d = Distance( ent->origin, portal_centre ); if( d < best_d ) { best = ent; best_d = d; } } } if( best == NULL ) { if( captureTextureId < 0 ) return; } else { if( !VectorCompare( best->origin, best->origin2 ) ) // portal mirror = qfalse; best->rtype = NUM_RTYPES; } prevRenderFlags = rn.renderFlags; if( !R_PushRefInst() ) { return; } VectorCopy( rn.viewOrigin, viewerOrigin ); setup_and_render: if( refraction ) { VectorInverse( portal_plane->normal ); portal_plane->dist = -portal_plane->dist - 1; CategorizePlane( portal_plane ); VectorCopy( rn.viewOrigin, origin ); Matrix3_Copy( rn.refdef.viewaxis, axis ); VectorCopy( viewerOrigin, rn.pvsOrigin ); rn.renderFlags = RF_PORTALVIEW; if( !mirror ) rn.renderFlags |= RF_PVSCULL; } else if( mirror ) { VectorReflect( rn.viewOrigin, portal_plane->normal, portal_plane->dist, origin ); VectorReflect( &rn.viewAxis[AXIS_FORWARD], portal_plane->normal, 0, &axis[AXIS_FORWARD] ); VectorReflect( &rn.viewAxis[AXIS_RIGHT], portal_plane->normal, 0, &axis[AXIS_RIGHT] ); VectorReflect( &rn.viewAxis[AXIS_UP], portal_plane->normal, 0, &axis[AXIS_UP] ); Matrix3_Normalize( axis ); VectorCopy( viewerOrigin, rn.pvsOrigin ); rn.renderFlags = RF_MIRRORVIEW|RF_FLIPFRONTFACE; } else { vec3_t tvec; mat3_t A, B, C, rot; // build world-to-portal rotation matrix VectorNegate( portal_plane->normal, tvec ); NormalVectorToAxis( tvec, A ); // build portal_dest-to-world rotation matrix ByteToDir( best->frame, tvec ); NormalVectorToAxis( tvec, B ); Matrix3_Transpose( B, C ); // multiply to get world-to-world rotation matrix Matrix3_Multiply( C, A, rot ); // translate view origin VectorSubtract( rn.viewOrigin, best->origin, tvec ); Matrix3_TransformVector( rot, tvec, origin ); VectorAdd( origin, best->origin2, origin ); Matrix3_Transpose( A, B ); Matrix3_Multiply( rn.viewAxis, B, rot ); Matrix3_Multiply( best->axis, rot, B ); Matrix3_Transpose( C, A ); Matrix3_Multiply( B, A, axis ); // set up portal_plane VectorCopy( &axis[AXIS_FORWARD], portal_plane->normal ); portal_plane->dist = DotProduct( best->origin2, portal_plane->normal ); CategorizePlane( portal_plane ); // for portals, vis data is taken from portal origin, not // view origin, because the view point moves around and // might fly into (or behind) a wall rn.renderFlags = RF_PORTALVIEW|RF_PVSCULL; VectorCopy( best->origin2, rn.pvsOrigin ); VectorCopy( best->origin2, rn.lodOrigin ); // ignore entities, if asked politely if( best->renderfx & RF_NOPORTALENTS ) rn.renderFlags |= RF_NOENTS; } rn.renderFlags |= (prevRenderFlags & RF_SOFT_PARTICLES); rn.refdef.rdflags &= ~( RDF_UNDERWATER|RDF_CROSSINGWATER ); rn.shadowGroup = NULL; rn.meshlist = &r_portallist; rn.renderFlags |= RF_CLIPPLANE; rn.clipPlane = *portal_plane; rn.farClip = R_DefaultFarClip(); rn.clipFlags |= ( 1<<5 ); rn.frustum[5] = *portal_plane; CategorizePlane( &rn.frustum[5] ); // if we want to render to a texture, initialize texture // but do not try to render to it more than once if( captureTextureId >= 0 ) { int texFlags = shader->flags & SHADER_NO_TEX_FILTERING ? IT_NOFILTERING : 0; captureTexture = R_GetPortalTexture( rsc.refdef.width, rsc.refdef.height, texFlags, rsc.frameCount ); portalTexures[captureTextureId] = captureTexture; if( !captureTexture ) { // couldn't register a slot for this plane goto done; } x = y = 0; w = captureTexture->upload_width; h = captureTexture->upload_height; rn.refdef.width = w; rn.refdef.height = h; rn.refdef.x = 0; rn.refdef.y = 0; rn.fbColorAttachment = captureTexture; // no point in capturing the depth buffer due to oblique frustum messing up // the far plane and depth values rn.fbDepthAttachment = NULL; Vector4Set( rn.viewport, rn.refdef.x + x, rn.refdef.y + y, w, h ); Vector4Set( rn.scissor, rn.refdef.x + x, rn.refdef.y + y, w, h ); } else { // no point in capturing the depth buffer due to oblique frustum messing up // the far plane and depth values rn.fbDepthAttachment = NULL; Vector4Set( rn.scissor, rn.refdef.x + x, rn.refdef.y + y, w, h ); } VectorCopy( origin, rn.refdef.vieworg ); Matrix3_Copy( axis, rn.refdef.viewaxis ); R_RenderView( &rn.refdef ); if( doRefraction && !refraction && ( shader->flags & SHADER_PORTAL_CAPTURE2 ) ) { refraction = qtrue; captureTexture = NULL; captureTextureId = 1; goto setup_and_render; } done: portalSurface->texures[0] = portalTexures[0]; portalSurface->texures[1] = portalTexures[1]; R_PopRefInst( rn.fbDepthAttachment != NULL ? 0 : GL_DEPTH_BUFFER_BIT ); }
void MSG_ReadDir( msg_t *msg, vec3_t dir ) { ByteToDir( MSG_ReadByte( msg ), dir ); }
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; playerEntity_t *pe; fxParent_t fxParent; es = ¢->currentState; pe = ¢->pe; event = es->event & ~EV_EVENT_BITS; if ( cg_debugEvents.integer ) { CG_Printf( "ent:%3i event:%3i ", es->number, event ); } if ( !event ) { DEBUGNAME("ZEROEVENT"); return; } CG_DemoEntityEvent( cent ); clientNum = es->clientNum; if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) { clientNum = 0; } ci = &cgs.clientinfo[ clientNum ]; switch ( es->eType ) { case ET_PLAYER: case ET_INVISIBLE: if ( ci->hide || !ci->infoValid ) return; case ET_MISSILE: if ( cg.defrag.detected && ( ci->hide || !ci->infoValid)) return; } if (cg.defrag.detected) { switch ( event ) { case EV_PLAYER_TELEPORT_IN: case EV_PLAYER_TELEPORT_OUT: case EV_MISSILE_HIT: case EV_MISSILE_MISS: case EV_MISSILE_MISS_METAL: case EV_RAILTRAIL: case EV_BULLET: case EV_BULLET_HIT_FLESH: case EV_BULLET_HIT_WALL: case EV_SHOTGUN: if ( ci->hide || !ci->infoValid ) return; } } 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 ); // smooth landing z changes pe->landChange = -8; pe->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" ) ); pe->landChange = -16; pe->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 pe->landChange = -24; pe->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 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 - pe->stepTime; if (delta < STEP_TIME) { oldStep = pe->stepChange * (STEP_TIME - delta) / STEP_TIME; } else { oldStep = 0; } // add this amount step = 4 * (event - EV_STEP_4 + 1 ); pe->stepChange = oldStep + step; if ( pe->stepChange > MAX_STEP_CHANGE ) { pe->stepChange = MAX_STEP_CHANGE; } pe->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; 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) { } else { trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) ); } // show icon and name on status bar if ( cg.playerCent && es->number == cg.playerCent->currentState.number ) { 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 ) { if( cg.playerCent ) trap_S_StartSound (NULL, cg.playerCent->currentState.number, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) ); else trap_S_StartSound (NULL, ENTITYNUM_NONE, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) ); } // show icon and name on status bar if ( cg.playerCent && es->number == cg.playerCent->currentState.number ) { 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"); VectorCopy( position, fxParent.origin ); fxParent.origin[2] -= 24; fxParent.flags = FXP_ORIGIN; trap_FX_Run( cgs.fx.player.teleportIn, &fxParent, cent ); break; 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"); VectorCopy( position, fxParent.origin ); fxParent.origin[2] -= 24; fxParent.flags = FXP_ORIGIN; trap_FX_Run( cgs.fx.player.teleportOut, &fxParent, cent ); break; 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_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 the end was on a nomark surface, don't make an explosion CG_RailTrail( ci, es->origin2, es->pos.trBase ); if ( es->eventParm != 255 ) { ByteToDir( es->eventParm, dir ); CG_MissileHitWall( es->weapon, es->clientNum, 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 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) { CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound ); } else if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) { 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) { CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound ); } else if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) { 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; default: break; } break; } case EV_PAIN: // local player sounds are triggered in CG_CheckLocalSounds, // so ignore events on the player DEBUGNAME("EV_PAIN"); if ( cent->currentState.number != cg.snap->ps.clientNum ) { CG_PainEvent( cent, es->eventParm ); } break; case EV_DEATH1: case EV_DEATH2: case EV_DEATH3: DEBUGNAME("EV_DEATHx"); trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, va("*death%i.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 ); } if (cg_gibDirectional.integer == 1) { float speed; VectorCopy( cent->currentState.pos.trDelta, dir ); speed = VectorNormalize( dir ); if ( speed > 500 ) { VectorScale( dir, 500, dir ); CG_GibPlayer( cent->lerpOrigin, dir ); } else { CG_GibPlayer( cent->lerpOrigin, cent->currentState.pos.trDelta ); } } else if (cg_gibDirectional.integer == 2 && es->eventParm >= 0 && es->eventParm < MAX_CLIENTS && (cg_entities[es->eventParm].currentValid || cg.snap->ps.clientNum == es->eventParm)) { if ( cg.snap->ps.clientNum == es->eventParm) { VectorSubtract( cent->lerpOrigin, cg.predictedPlayerState.origin, dir ); } else { VectorSubtract( cent->lerpOrigin, cg_entities[es->eventParm].lerpOrigin, dir ); } VectorNormalize( dir ); VectorScale( dir, 300, dir ); CG_GibPlayer( cent->lerpOrigin, dir ); } else { CG_GibPlayer( cent->lerpOrigin, vec3_origin ); } 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"); if (mov_debug.integer) CG_Printf( "Unknown event: %i\n", event ); break; } }
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_BANDAGE: DEBUGNAME("EV_BANDAGE"); if (clientNum == cg.predictedPlayerState.clientNum) { CG_ZoomReset_f(); } trap_S_StartSound(NULL, es->number, CHAN_BODY, cgs.media.bandageSound); break; 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_FOOTSTEP_LADDER: //Xamis DEBUGNAME("EV_FOOTSTEP_LADDER"); { trap_S_StartSound(NULL, es->number, CHAN_BODY, cgs.media.ladderSound[rand()&3]); } break; case EV_LEDGEGRAB: //Xamis DEBUGNAME("EV_LEDGEGRAB"); { trap_S_StartSound(NULL, es->number, CHAN_BODY, cgs.media.ledgeSound); } 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 = -32; cg.landTime = cg.time; } break; case EV_CURBSTOMP: DEBUGNAME("EV_CURBSTOMP"); trap_S_StartSound(NULL, es->number, CHAN_AUTO, cgs.media.stompSound); 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" ) ); //Xamis { 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_BLEED: DEBUGNAME("EV_BLEED"); CG_CreateBleeder(es->pos.trBase, 10, cent->currentState.clientNum); // CG_PlayerBleed(cent->currentState.clientNum, 10, es->pos.trBase, dir ); break; case EV_WALLJUMP: DEBUGNAME("EV_WALLJUMP") 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 ]; // trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) ); //Disable sounds for powerup -- Xamis // 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 { 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) { trap_S_StartSound(NULL, es->number, CHAN_AUTO, cgs.media.noammoSound); } break; case EV_NONADES: DEBUGNAME("EV_NONADES"); if (clientNum == cg.predictedPlayerState.clientNum) { CG_WeaponSort(); } break; case EV_POWERSLIDE: CG_HasteTrail(cent); break; case EV_CHANGE_WEAPON: DEBUGNAME("EV_CHANGE_WEAPON"); trap_S_StartSound(NULL, es->number, CHAN_AUTO, cgs.media.selectSound); break; case EV_WEAPON_DROPPED: DEBUGNAME("EV_WEAPON_DROPPED"); if (clientNum == cg.predictedPlayerState.clientNum) { //CG_Printf("EV_WEAPON_DROPPED\n"); CG_WeaponSort(); } break; case EV_FIRE_WEAPON: DEBUGNAME("EV_FIRE_WEAPON"); CG_FireWeapon(cent); break; case EV_ZOOM_RESET: if (clientNum == cg.predictedPlayerState.clientNum) { CG_ZoomReset_f(); } break; case EV_EJECT_CASING: { entityState_t *ent; weaponInfo_t *weap; ent = ¢->currentState; weap = &cg_weapons[ ent->weapon ]; weap->ejectBrassFunc(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 ); //disable sound --Xamis 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 );//disable sound --Xamis 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_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_GAMESTATE: trap_Cvar_Set("ui_gamestate", va("%i", es->eventParm)); 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_DRAW_ROUND: CG_AddBufferedSound(cgs.media.roundDrawSound); break; 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_BOMB) 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_BOMB) 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_BOMB) 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_BOMB) 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; #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 (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 (clientNum == cg.predictedPlayerState.clientNum) { CG_ZoomReset_f(); } 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_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; //Xamis case EV_BREAK_GLASS: DEBUGNAME("EV_BREAK_GLASS"); trap_S_StartSound(NULL, es->number, CHAN_BODY, cgs.media.glassSound); CG_BreakGlass(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_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 ) { // // movement generated events // 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 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: 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; // // weapon events // 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_FireWeapon( cent, WPM_PRIMARY ); break; case EV_FIRE_WEAPON2: CG_FireWeapon( cent, WPM_SECONDARY ); break; case EV_FIRE_WEAPON3: CG_FireWeapon( cent, WPM_TERTIARY ); break; //================================================================= // // other events // case EV_PLAYER_TELEPORT_IN: //deprecated break; case EV_PLAYER_TELEPORT_OUT: CG_PlayerDisconnect( position ); break; case EV_BUILD_CONSTRUCT: //do something useful here break; case EV_BUILD_DESTROY: //do something useful here break; case EV_RPTUSE_SOUND: 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; //ROTAXfun case EV_ACIDBOMB_BOUNCE: if( rand( ) & 1 ) trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.acidBombBounceSound1 ); else trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.acidBombBounceSound2 ); break; // // missile impacts // case EV_MISSILE_HIT: ByteToDir( es->eventParm, dir ); CG_MissileHitEntity( es->weapon, es->generic1, position, dir, es->otherEntityNum, es->torsoAnim ); break; case EV_MISSILE_MISS: ByteToDir( es->eventParm, dir ); CG_MissileHitWall( es->weapon, es->generic1, 0, position, dir, IMPACTSOUND_DEFAULT, es->torsoAnim ); break; case EV_MISSILE_MISS_METAL: ByteToDir( es->eventParm, dir ); CG_MissileHitWall( es->weapon, es->generic1, 0, position, dir, IMPACTSOUND_METAL, es->torsoAnim ); break; case EV_HUMAN_BUILDABLE_EXPLOSION: ByteToDir( es->eventParm, dir ); CG_HumanBuildableExplosion( position, dir, es->modelindex );//ROTAXfun break; case EV_ALIEN_BUILDABLE_EXPLOSION: ByteToDir( es->eventParm, dir ); CG_AlienBuildableExplosion( position, dir, es->modelindex );//ROTAXfun if ( es->modelindex == BA_A_BUSH ) CG_AlienBushExplosion( 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_BULLET_HIT_WALL: ByteToDir( es->eventParm, dir ); CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD ); break; case EV_BULLET_HIT_FLESH: CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm ); break; case EV_SHOTGUN: CG_ShotgunFire( es ); 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: if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_ALIENS ) { trap_S_StartLocalSound( cgs.media.alienOvermindAttack, CHAN_ANNOUNCER ); CG_CenterPrint( "The Overmind is under attack!", 200, GIANTCHAR_WIDTH * 4 ); } break; case EV_OVERMIND_DYING: if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_ALIENS ) { trap_S_StartLocalSound( cgs.media.alienOvermindDying, CHAN_ANNOUNCER ); CG_CenterPrint( "The Overmind is dying!", 200, GIANTCHAR_WIDTH * 4 ); } break; case EV_DCC_ATTACK: if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_HUMANS ) { //trap_S_StartLocalSound( cgs.media.humanDCCAttack, CHAN_ANNOUNCER ); 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.stats[ STAT_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: // the parameter is the healer's entity number { const int healerNum = es->eventParm; const char *configstring; const char *name; if( healerNum != clientNum ) { if( healerNum == cg.clientNum ) { configstring = CG_ConfigString( clientNum + CS_PLAYERS ); // isolate the player's name name = Info_ValueForKey( configstring, "n" ); CG_Printf( S_COLOR_CYAN "You bandaged " S_COLOR_WHITE "%s" S_COLOR_CYAN "'s wounds.\n", name ); } else if( clientNum == cg.clientNum ) { configstring = CG_ConfigString( healerNum + CS_PLAYERS ); // isolate the player's name name = Info_ValueForKey( configstring, "n" ); CG_Printf( S_COLOR_WHITE "%s" S_COLOR_CYAN " bandaged your wounds.\n", name ); } } } 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; default: CG_Error( "Unknown event: %i", event ); break; } }
/* * CG_FirePlayerStateEvents * This events are only received by this client, and only affect it. */ static void CG_FirePlayerStateEvents( void ) { unsigned int event, parm, i, count; vec3_t dir; if( !cg.frame.playerState.event ) return; if( cg.view.POVent != (int)cg.frame.playerState.POVnum ) return; for( count = 0; count < 2; count++ ) { // first byte is event number, second is parm event = cg.frame.playerState.event[count] & 127; parm = cg.frame.playerState.eventParm[count] & 0xFF; switch( event ) { case PSEV_HIT: if( parm > 6 ) break; if( parm < 4 ) { // hit of some caliber trap_S_StartGlobalSound( CG_MediaSfx( cgs.media.sfxWeaponHit[parm] ), CHAN_AUTO, cg_volume_hitsound->value ); CG_ScreenCrosshairDamageUpdate(); } else if( parm == 4 ) // killed an enemy { trap_S_StartGlobalSound( CG_MediaSfx( cgs.media.sfxWeaponKill ), CHAN_AUTO, cg_volume_hitsound->value ); CG_ScreenCrosshairDamageUpdate(); } else { // hit a teammate trap_S_StartGlobalSound( CG_MediaSfx( cgs.media.sfxWeaponHitTeam ), CHAN_AUTO, cg_volume_hitsound->value ); if( cg_showhelp->integer ) { if( random() <= 0.5f ) CG_CenterPrint( "Don't shoot at members of your team!" ); else CG_CenterPrint( "You are shooting at your teammates!" ); } } break; case PSEV_PICKUP: if( cg_pickup_flash->integer && !cg.view.thirdperson ) CG_StartColorBlendEffect( 1.0f, 1.0f, 1.0f, 0.25f, 150 ); // auto-switch if( cg_weaponAutoSwitch->integer && ( parm > WEAP_NONE && parm < WEAP_TOTAL ) ) { if( !cgs.demoPlaying && cg.predictedPlayerState.pmove.pm_type == PM_NORMAL && cg.predictedPlayerState.POVnum == cgs.playerNum + 1 ) { // auto-switch only works when the user didn't have the just-picked weapon if( !cg.oldFrame.playerState.inventory[parm] ) { // switch when player's only weapon is gunblade if( cg_weaponAutoSwitch->integer == 2 ) { for( i = WEAP_GUNBLADE + 1; i < WEAP_TOTAL; i++ ) { if( i == parm ) continue; if( cg.predictedPlayerState.inventory[i] ) break; } if( i == WEAP_TOTAL ) // didn't have any weapon CG_UseItem( va( "%i", parm ) ); } // switch when the new weapon improves player's selected weapon else if( cg_weaponAutoSwitch->integer == 1 ) { unsigned int best = WEAP_GUNBLADE; for( i = WEAP_GUNBLADE + 1; i < WEAP_TOTAL; i++ ) { if( i == parm ) continue; if( cg.predictedPlayerState.inventory[i] ) best = i; } if( best < parm ) CG_UseItem( va( "%i", parm ) ); } } } } break; case PSEV_DAMAGE_20: ByteToDir( parm, dir ); CG_DamageIndicatorAdd( 20, dir ); break; case PSEV_DAMAGE_40: ByteToDir( parm, dir ); CG_DamageIndicatorAdd( 40, dir ); break; case PSEV_DAMAGE_60: ByteToDir( parm, dir ); CG_DamageIndicatorAdd( 60, dir ); break; case PSEV_DAMAGE_80: ByteToDir( parm, dir ); CG_DamageIndicatorAdd( 80, dir ); break; case PSEV_INDEXEDSOUND: if( cgs.soundPrecache[parm] ) trap_S_StartGlobalSound( cgs.soundPrecache[parm], CHAN_AUTO, cg_volume_effects->value ); break; case PSEV_ANNOUNCER: CG_AddAnnouncerEvent( cgs.soundPrecache[parm], qfalse ); break; case PSEV_ANNOUNCER_QUEUED: CG_AddAnnouncerEvent( cgs.soundPrecache[parm], qtrue ); break; default: break; } } }
/* * CG_EntityEvent */ void CG_EntityEvent( entity_state_t *ent, int ev, int parm, qboolean predicted ) { //static orientation_t projection; vec3_t dir; qboolean viewer = ISVIEWERENTITY( ent->number ); vec4_t color; int weapon = 0, fireMode = 0, count = 0; if( viewer && ( ev < PREDICTABLE_EVENTS_MAX ) && ( predicted != cg.view.playerPrediction ) ) return; switch( ev ) { case EV_NONE: default: break; // PREDICTABLE EVENTS case EV_WEAPONACTIVATE: CG_PModel_AddAnimation( ent->number, 0, TORSO_WEAPON_SWITCHIN, 0, EVENT_CHANNEL ); weapon = ( parm & ~EV_INVERSE ); fireMode = ( parm & EV_INVERSE ) ? FIRE_MODE_STRONG : FIRE_MODE_WEAK; if( predicted ) { cg_entities[ent->number].current.weapon = weapon; if( fireMode == FIRE_MODE_STRONG ) cg_entities[ent->number].current.effects |= EF_STRONG_WEAPON; CG_ViewWeapon_RefreshAnimation( &cg.weapon ); } if( viewer ) cg.predictedWeaponSwitch = 0; if( viewer ) trap_S_StartGlobalSound( CG_MediaSfx( cgs.media.sfxWeaponUp ), CHAN_AUTO, cg_volume_effects->value ); else trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxWeaponUp ), ent->origin, CHAN_AUTO, cg_volume_effects->value, ATTN_NORM ); break; case EV_SMOOTHREFIREWEAPON: // the server never sends this event if( predicted ) { weapon = ( parm & ~EV_INVERSE ); fireMode = ( parm & EV_INVERSE ) ? FIRE_MODE_STRONG : FIRE_MODE_WEAK; cg_entities[ent->number].current.weapon = weapon; if( fireMode == FIRE_MODE_STRONG ) cg_entities[ent->number].current.effects |= EF_STRONG_WEAPON; CG_ViewWeapon_RefreshAnimation( &cg.weapon ); if( weapon == WEAP_LASERGUN ) CG_Event_LaserBeam( ent->number, weapon, fireMode ); } break; case EV_FIREWEAPON: weapon = ( parm & ~EV_INVERSE ); fireMode = ( parm & EV_INVERSE ) ? FIRE_MODE_STRONG : FIRE_MODE_WEAK; if( predicted ) { cg_entities[ent->number].current.weapon = weapon; if( fireMode == FIRE_MODE_STRONG ) cg_entities[ent->number].current.effects |= EF_STRONG_WEAPON; } CG_FireWeaponEvent( ent->number, weapon, fireMode ); // riotgun bullets, electrobolt and instagun beams are predicted when the weapon is fired if( predicted ) { vec3_t origin; if( ( weapon == WEAP_ELECTROBOLT #ifndef ELECTROBOLT_TEST && fireMode == FIRE_MODE_STRONG #endif ) || weapon == WEAP_INSTAGUN ) { VectorCopy( cg.predictedPlayerState.pmove.origin, origin ); origin[2] += cg.predictedPlayerState.viewheight; AngleVectors( cg.predictedPlayerState.viewangles, dir, NULL, NULL ); CG_Event_WeaponBeam( origin, dir, cg.predictedPlayerState.POVnum, weapon, fireMode ); } else if( weapon == WEAP_RIOTGUN || weapon == WEAP_MACHINEGUN ) { int seed = cg.predictedEventTimes[EV_FIREWEAPON] & 255; VectorCopy( cg.predictedPlayerState.pmove.origin, origin ); origin[2] += cg.predictedPlayerState.viewheight; AngleVectors( cg.predictedPlayerState.viewangles, dir, NULL, NULL ); if( weapon == WEAP_RIOTGUN ) CG_Event_FireRiotgun( origin, dir, weapon, fireMode, seed, cg.predictedPlayerState.POVnum ); else CG_Event_FireMachinegun( origin, dir, weapon, fireMode, seed, cg.predictedPlayerState.POVnum ); } else if( weapon == WEAP_LASERGUN ) { CG_Event_LaserBeam( ent->number, weapon, fireMode ); } } break; case EV_ELECTROTRAIL: // check the owner for predicted case if( ISVIEWERENTITY( parm ) && ( ev < PREDICTABLE_EVENTS_MAX ) && ( predicted != cg.view.playerPrediction ) ) return; CG_Event_WeaponBeam( ent->origin, ent->origin2, parm, WEAP_ELECTROBOLT, ent->firemode ); break; case EV_INSTATRAIL: // check the owner for predicted case if( ISVIEWERENTITY( parm ) && ( ev < PREDICTABLE_EVENTS_MAX ) && ( predicted != cg.view.playerPrediction ) ) return; CG_Event_WeaponBeam( ent->origin, ent->origin2, parm, WEAP_INSTAGUN, FIRE_MODE_STRONG ); break; case EV_FIRE_RIOTGUN: case EV_FIRE_BULLET: { // check the owner for predicted case if( ISVIEWERENTITY( ent->ownerNum ) && ( ev < PREDICTABLE_EVENTS_MAX ) && ( predicted != cg.view.playerPrediction ) ) return; if( ev == EV_FIRE_RIOTGUN ) CG_Event_FireRiotgun( ent->origin, ent->origin2, ( ent->weapon & ~EV_INVERSE ), ( ent->weapon & EV_INVERSE ), parm, ent->ownerNum ); else CG_Event_FireMachinegun( ent->origin, ent->origin2, ( ent->weapon & ~EV_INVERSE ), ( ent->weapon & EV_INVERSE ), parm, ent->ownerNum ); } break; case EV_NOAMMOCLICK: if( viewer ) trap_S_StartGlobalSound( CG_MediaSfx( cgs.media.sfxWeaponUpNoAmmo ), CHAN_ITEM, cg_volume_effects->value ); else trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxWeaponUpNoAmmo ), ent->origin, CHAN_ITEM, cg_volume_effects->value, ATTN_IDLE ); break; case EV_DASH: CG_Event_Dash( ent, parm ); break; case EV_WALLJUMP: case EV_WALLJUMP_FAILED: CG_Event_WallJump( ent, parm, ev ); break; case EV_DOUBLEJUMP: CG_Event_DoubleJump( ent, parm ); break; case EV_JUMP: CG_Event_Jump( ent, parm ); break; case EV_JUMP_PAD: CG_TouchJumpPad( ent->number ); break; case EV_FALL: CG_Event_Fall( ent, parm ); break; // NON PREDICTABLE EVENTS case EV_WEAPONDROP: // deactivate is not predictable CG_PModel_AddAnimation( ent->number, 0, TORSO_WEAPON_SWITCHOUT, 0, EVENT_CHANNEL ); break; case EV_SEXEDSOUND: if( parm == 2 ) CG_SexedSound( ent->number, CHAN_AUTO, S_PLAYER_GASP, cg_volume_players->value ); else if( parm == 1 ) CG_SexedSound( ent->number, CHAN_AUTO, S_PLAYER_DROWN, cg_volume_players->value ); break; case EV_PAIN: CG_Event_Pain( ent, parm ); break; case EV_DIE: CG_Event_Die( ent, parm ); break; case EV_GIB: break; case EV_EXPLOSION1: CG_GenericExplosion( ent->origin, vec3_origin, FIRE_MODE_WEAK, parm * 8 ); break; case EV_EXPLOSION2: CG_GenericExplosion( ent->origin, vec3_origin, FIRE_MODE_STRONG, parm * 16 ); break; case EV_GREEN_LASER: CG_GreenLaser( ent->origin, ent->origin2 ); break; case EV_PNODE: color[0] = COLOR_R( ent->colorRGBA ) * ( 1.0 / 255.0 ); color[1] = COLOR_G( ent->colorRGBA ) * ( 1.0 / 255.0 ); color[2] = COLOR_B( ent->colorRGBA ) * ( 1.0 / 255.0 ); color[3] = COLOR_A( ent->colorRGBA ) * ( 1.0 / 255.0 ); CG_PLink( ent->origin, ent->origin2, color, parm ); break; case EV_SPARKS: ByteToDir( parm, dir ); if( ent->damage > 0 ) { count = (int)( ent->damage * 0.25f ); clamp( count, 1, 10 ); } else count = 6; CG_ParticleEffect( ent->origin, dir, 1.0f, 0.67f, 0.0f, count ); break; case EV_BULLET_SPARKS: ByteToDir( parm, dir ); CG_BulletExplosion( ent->origin, dir, NULL ); CG_ParticleEffect( ent->origin, dir, 1.0f, 0.67f, 0.0f, 6 ); trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxRic[rand()&2] ), ent->origin, CHAN_AUTO, cg_volume_effects->value, ATTN_STATIC ); break; case EV_LASER_SPARKS: ByteToDir( parm, dir ); CG_ParticleEffect2( ent->origin, dir, COLOR_R( ent->colorRGBA ) * ( 1.0 / 255.0 ), COLOR_G( ent->colorRGBA ) * ( 1.0 / 255.0 ), COLOR_B( ent->colorRGBA ) * ( 1.0 / 255.0 ), ent->eventCount ); break; case EV_GESTURE: CG_SexedSound( ent->number, CHAN_BODY, "*taunt", cg_volume_players->value ); break; case EV_DROP: CG_PModel_AddAnimation( ent->number, 0, TORSO_DROP, 0, EVENT_CHANNEL ); break; case EV_SPOG: CG_SmallPileOfGibs( ent->origin, parm, ent->origin2 ); break; case EV_ITEM_RESPAWN: cg_entities[ent->number].respawnTime = cg.time; trap_S_StartRelativeSound( CG_MediaSfx( cgs.media.sfxItemRespawn ), ent->number, CHAN_AUTO, cg_volume_effects->value, ATTN_IDLE ); break; case EV_PLAYER_RESPAWN: if( (unsigned)ent->ownerNum == cgs.playerNum + 1 ) { CG_ResetKickAngles(); CG_ResetColorBlend(); CG_ResetDamageIndicator(); } // fallthrough case EV_PLAYER_TELEPORT_IN: if( ISVIEWERENTITY( ent->ownerNum ) ) { trap_S_StartGlobalSound( CG_MediaSfx( cgs.media.sfxTeleportIn ), CHAN_AUTO, cg_volume_effects->value ); } else { trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxTeleportIn ), ent->origin, CHAN_AUTO, cg_volume_effects->value, ATTN_NORM ); } if( ent->ownerNum && ent->ownerNum < gs.maxclients + 1 ) cg_entities[ent->ownerNum].localEffects[LOCALEFFECT_EV_PLAYER_TELEPORT_IN] = cg.time; break; case EV_PLAYER_TELEPORT_OUT: if( ISVIEWERENTITY( ent->ownerNum ) ) { trap_S_StartGlobalSound( CG_MediaSfx( cgs.media.sfxTeleportOut ), CHAN_AUTO, cg_volume_effects->value ); } else { trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxTeleportOut ), ent->origin, CHAN_AUTO, cg_volume_effects->value, ATTN_NORM ); } if( ent->ownerNum && ent->ownerNum < gs.maxclients + 1 ) { cg_entities[ent->ownerNum].localEffects[LOCALEFFECT_EV_PLAYER_TELEPORT_OUT] = cg.time; VectorCopy( ent->origin, cg_entities[ent->ownerNum].teleportedFrom ); } break; case EV_PLASMA_EXPLOSION: ByteToDir( parm, dir ); CG_PlasmaExplosion( ent->origin, dir, ent->firemode, (float)ent->weapon * 8.0f ); if( ent->firemode == FIRE_MODE_STRONG ) { trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxPlasmaStrongHit ), ent->origin, CHAN_AUTO, cg_volume_effects->value, ATTN_IDLE ); CG_StartKickAnglesEffect( ent->origin, 50, ent->weapon * 8, 100 ); } else { trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxPlasmaWeakHit ), ent->origin, CHAN_AUTO, cg_volume_effects->value, ATTN_IDLE ); CG_StartKickAnglesEffect( ent->origin, 30, ent->weapon * 8, 75 ); } break; case EV_BOLT_EXPLOSION: ByteToDir( parm, dir ); CG_BoltExplosionMode( ent->origin, dir, ent->firemode ); break; case EV_INSTA_EXPLOSION: ByteToDir( parm, dir ); CG_InstaExplosionMode( ent->origin, dir, ent->firemode ); break; case EV_GRENADE_EXPLOSION: if( parm ) { // we have a direction ByteToDir( parm, dir ); CG_GrenadeExplosionMode( ent->origin, dir, ent->firemode, (float)ent->weapon*8.0f ); } else { // no direction CG_GrenadeExplosionMode( ent->origin, vec3_origin, ent->firemode, (float)ent->weapon*8.0f ); } if( ent->firemode == FIRE_MODE_STRONG ) CG_StartKickAnglesEffect( ent->origin, 135, ent->weapon*8, 325 ); else CG_StartKickAnglesEffect( ent->origin, 125, ent->weapon*8, 300 ); break; case EV_ROCKET_EXPLOSION: ByteToDir( parm, dir ); CG_RocketExplosionMode( ent->origin, dir, ent->firemode, (float)ent->weapon * 8.0f ); if( ent->firemode == FIRE_MODE_STRONG ) CG_StartKickAnglesEffect( ent->origin, 135, ent->weapon * 8, 300 ); else CG_StartKickAnglesEffect( ent->origin, 125, ent->weapon * 8, 275 ); break; case EV_GRENADE_BOUNCE: if( parm == FIRE_MODE_STRONG ) trap_S_StartRelativeSound( CG_MediaSfx( cgs.media.sfxGrenadeStrongBounce[rand()&1] ), ent->number, CHAN_AUTO, cg_volume_effects->value, ATTN_IDLE ); else trap_S_StartRelativeSound( CG_MediaSfx( cgs.media.sfxGrenadeWeakBounce[rand()&1] ), ent->number, CHAN_AUTO, cg_volume_effects->value, ATTN_IDLE ); break; case EV_BLADE_IMPACT: CG_BladeImpact( ent->origin, ent->origin2 ); break; case EV_GUNBLADEBLAST_IMPACT: ByteToDir( parm, dir ); CG_GunBladeBlastImpact( ent->origin, dir, (float)ent->weapon*8 ); if( ent->skinnum > 64 ) { trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxGunbladeStrongHit[2] ), ent->origin, CHAN_AUTO, cg_volume_effects->value, ATTN_DISTANT ); } else if( ent->skinnum > 34 ) { trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxGunbladeStrongHit[1] ), ent->origin, CHAN_AUTO, cg_volume_effects->value, ATTN_NORM ); } else { trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxGunbladeStrongHit[0] ), ent->origin, CHAN_AUTO, cg_volume_effects->value, ATTN_IDLE ); } //ent->skinnum is knockback value CG_StartKickAnglesEffect( ent->origin, ent->skinnum*8, ent->weapon*8, 200 ); break; case EV_BLOOD: if( cg_showBloodTrail->integer == 2 && ISVIEWERENTITY( ent->ownerNum ) ) break; ByteToDir( parm, dir ); CG_BloodDamageEffect( ent->origin, dir, ent->damage ); CG_CartoonHitEffect( ent->origin, dir, ent->damage ); break; // func movers case EV_PLAT_HIT_TOP: case EV_PLAT_HIT_BOTTOM: case EV_PLAT_START_MOVING: case EV_DOOR_HIT_TOP: case EV_DOOR_HIT_BOTTOM: case EV_DOOR_START_MOVING: case EV_BUTTON_FIRE: case EV_TRAIN_STOP: case EV_TRAIN_START: { vec3_t so; CG_GetEntitySpatilization( ent->number, so, NULL ); trap_S_StartFixedSound( cgs.soundPrecache[parm], so, CHAN_AUTO, cg_volume_effects->value, ATTN_STATIC ); } break; case EV_VSAY: CG_StartVoiceTokenEffect( ent->ownerNum, EV_VSAY, parm ); break; } }
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; } }
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; } }
/* * R_DrawPortalSurface * * Renders the portal view and captures the results from framebuffer if * we need to do a $portalmap stage. Note that for $portalmaps we must * use a different viewport. */ static void R_DrawPortalSurface( portalSurface_t *portalSurface ) { unsigned int i; int x, y, w, h; float dist, d, best_d; vec3_t viewerOrigin; vec3_t origin; mat3_t axis; entity_t *ent, *best; cplane_t *portal_plane = &portalSurface->plane, *untransformed_plane = &portalSurface->untransformed_plane; const shader_t *shader = portalSurface->shader; vec_t *portal_centre = portalSurface->centre; bool mirror, refraction = false; image_t *captureTexture; int captureTextureId = -1; int prevRenderFlags = 0; bool prevFlipped; bool doReflection, doRefraction; image_t *portalTexures[2] = { NULL, NULL }; doReflection = doRefraction = true; if( shader->flags & SHADER_PORTAL_CAPTURE ) { shaderpass_t *pass; captureTexture = NULL; captureTextureId = 0; for( i = 0, pass = shader->passes; i < shader->numpasses; i++, pass++ ) { if( pass->program_type == GLSL_PROGRAM_TYPE_DISTORTION ) { if( ( pass->alphagen.type == ALPHA_GEN_CONST && pass->alphagen.args[0] == 1 ) ) { doRefraction = false; } else if( ( pass->alphagen.type == ALPHA_GEN_CONST && pass->alphagen.args[0] == 0 ) ) { doReflection = false; } break; } } } else { captureTexture = NULL; captureTextureId = -1; } x = y = 0; w = rn.refdef.width; h = rn.refdef.height; dist = PlaneDiff( rn.viewOrigin, portal_plane ); if( dist <= BACKFACE_EPSILON || !doReflection ) { if( !( shader->flags & SHADER_PORTAL_CAPTURE2 ) || !doRefraction ) { return; } // even if we're behind the portal, we still need to capture // the second portal image for refraction refraction = true; captureTexture = NULL; captureTextureId = 1; if( dist < 0 ) { VectorInverse( portal_plane->normal ); portal_plane->dist = -portal_plane->dist; } } mirror = true; // default to mirror view // it is stupid IMO that mirrors require a RT_PORTALSURFACE entity best = NULL; best_d = 100000000; for( i = 0; i < rn.numEntities; i++ ) { ent = R_NUM2ENT( rn.entities[i] ); if( ent->rtype != RT_PORTALSURFACE ) { continue; } d = PlaneDiff( ent->origin, untransformed_plane ); if( ( d >= -64 ) && ( d <= 64 ) ) { d = Distance( ent->origin, portal_centre ); if( d < best_d ) { best = ent; best_d = d; } } } if( best == NULL ) { if( captureTextureId < 0 ) { // still do a push&pop because to ensure the clean state if( R_PushRefInst() ) { R_PopRefInst(); } return; } } else { if( !VectorCompare( best->origin, best->origin2 ) ) { // portal mirror = false; } best->rtype = NUM_RTYPES; } prevRenderFlags = rn.renderFlags; prevFlipped = ( rn.refdef.rdflags & RDF_FLIPPED ) != 0; if( !R_PushRefInst() ) { return; } VectorCopy( rn.viewOrigin, viewerOrigin ); if( prevFlipped ) { VectorInverse( &rn.viewAxis[AXIS_RIGHT] ); } setup_and_render: if( refraction ) { VectorInverse( portal_plane->normal ); portal_plane->dist = -portal_plane->dist; CategorizePlane( portal_plane ); VectorCopy( rn.viewOrigin, origin ); Matrix3_Copy( rn.refdef.viewaxis, axis ); VectorCopy( viewerOrigin, rn.pvsOrigin ); rn.renderFlags |= RF_PORTALVIEW; if( prevFlipped ) { rn.renderFlags |= RF_FLIPFRONTFACE; } } else if( mirror ) { VectorReflect( rn.viewOrigin, portal_plane->normal, portal_plane->dist, origin ); VectorReflect( &rn.viewAxis[AXIS_FORWARD], portal_plane->normal, 0, &axis[AXIS_FORWARD] ); VectorReflect( &rn.viewAxis[AXIS_RIGHT], portal_plane->normal, 0, &axis[AXIS_RIGHT] ); VectorReflect( &rn.viewAxis[AXIS_UP], portal_plane->normal, 0, &axis[AXIS_UP] ); Matrix3_Normalize( axis ); VectorCopy( viewerOrigin, rn.pvsOrigin ); rn.renderFlags = ( prevRenderFlags ^ RF_FLIPFRONTFACE ) | RF_MIRRORVIEW; } else { vec3_t tvec; mat3_t A, B, C, rot; // build world-to-portal rotation matrix VectorNegate( portal_plane->normal, tvec ); NormalVectorToAxis( tvec, A ); // build portal_dest-to-world rotation matrix ByteToDir( best->frame, tvec ); NormalVectorToAxis( tvec, B ); Matrix3_Transpose( B, C ); // multiply to get world-to-world rotation matrix Matrix3_Multiply( C, A, rot ); // translate view origin VectorSubtract( rn.viewOrigin, best->origin, tvec ); Matrix3_TransformVector( rot, tvec, origin ); VectorAdd( origin, best->origin2, origin ); Matrix3_Transpose( A, B ); Matrix3_Multiply( rn.viewAxis, B, rot ); Matrix3_Multiply( best->axis, rot, B ); Matrix3_Transpose( C, A ); Matrix3_Multiply( B, A, axis ); // set up portal_plane VectorCopy( &axis[AXIS_FORWARD], portal_plane->normal ); portal_plane->dist = DotProduct( best->origin2, portal_plane->normal ); CategorizePlane( portal_plane ); // for portals, vis data is taken from portal origin, not // view origin, because the view point moves around and // might fly into (or behind) a wall VectorCopy( best->origin2, rn.pvsOrigin ); VectorCopy( best->origin2, rn.lodOrigin ); rn.renderFlags |= RF_PORTALVIEW; // ignore entities, if asked politely if( best->renderfx & RF_NOPORTALENTS ) { rn.renderFlags |= RF_ENVVIEW; } if( prevFlipped ) { rn.renderFlags |= RF_FLIPFRONTFACE; } } rn.refdef.rdflags &= ~( RDF_UNDERWATER | RDF_CROSSINGWATER | RDF_FLIPPED ); rn.meshlist = &r_portallist; rn.portalmasklist = NULL; rn.renderFlags |= RF_CLIPPLANE; rn.renderFlags &= ~RF_SOFT_PARTICLES; rn.clipPlane = *portal_plane; rn.nearClip = Z_NEAR; rn.farClip = R_DefaultFarClip(); rn.polygonFactor = POLYOFFSET_FACTOR; rn.polygonUnits = POLYOFFSET_UNITS; rn.clipFlags |= 16; rn.frustum[4] = *portal_plane; // nearclip CategorizePlane( &rn.frustum[4] ); // if we want to render to a texture, initialize texture // but do not try to render to it more than once if( captureTextureId >= 0 ) { int texFlags = shader->flags & SHADER_NO_TEX_FILTERING ? IT_NOFILTERING : 0; captureTexture = R_GetPortalTexture( rsc.refdef.width, rsc.refdef.height, texFlags, rsc.frameCount ); portalTexures[captureTextureId] = captureTexture; if( !captureTexture ) { // couldn't register a slot for this plane goto done; } x = y = 0; w = captureTexture->upload_width; h = captureTexture->upload_height; rn.refdef.width = w; rn.refdef.height = h; rn.refdef.x = 0; rn.refdef.y = 0; rn.renderTarget = captureTexture->fbo; rn.renderFlags |= RF_PORTAL_CAPTURE; Vector4Set( rn.viewport, rn.refdef.x + x, rn.refdef.y + y, w, h ); Vector4Set( rn.scissor, rn.refdef.x + x, rn.refdef.y + y, w, h ); } else { rn.renderFlags &= ~RF_PORTAL_CAPTURE; } VectorCopy( origin, rn.refdef.vieworg ); Matrix3_Copy( axis, rn.refdef.viewaxis ); R_SetupViewMatrices( &rn.refdef ); R_SetupFrustum( &rn.refdef, rn.nearClip, rn.farClip, rn.frustum, rn.frustumCorners ); R_SetupPVS( &rn.refdef ); R_RenderView( &rn.refdef ); if( doRefraction && !refraction && ( shader->flags & SHADER_PORTAL_CAPTURE2 ) ) { rn.renderFlags = prevRenderFlags; refraction = true; captureTexture = NULL; captureTextureId = 1; goto setup_and_render; } done: portalSurface->texures[0] = portalTexures[0]; portalSurface->texures[1] = portalTexures[1]; R_PopRefInst(); }