// this causes a compiler bug on mac MrC compiler static void CG_StepOffset( void ) { float steptime; int timeDelta; vec3_t normal; playerState_t *ps = &cg.predictedPlayerState; if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) { if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) VectorSet( normal, 0.0f, 0.0f, -1.0f ); else VectorCopy( ps->grapplePoint, normal ); } else VectorSet( normal, 0.0f, 0.0f, 1.0f ); steptime = BG_FindSteptimeForClass( ps->stats[ STAT_PCLASS ] ); // smooth out stair climbing timeDelta = cg.time - cg.stepTime; if( timeDelta < steptime ) { float stepChange = cg.stepChange * (steptime - timeDelta) / steptime; if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) VectorMA( cg.refdef.vieworg, -stepChange, normal, cg.refdef.vieworg ); else cg.refdef.vieworg[ 2 ] -= stepChange; } }
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_TEAM ] == TEAM_SPECTATOR ) steptime = 200; else steptime = BG_FindSteptimeForClass( cg.snap->ps.stats[ STAT_PCLASS ] ); 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 && 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: DEBUGNAME( "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: DEBUGNAME( "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: DEBUGNAME( "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: DEBUGNAME( "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: DEBUGNAME( "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: 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_FALLING: DEBUGNAME( "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 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 < 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: DEBUGNAME( "EV_JUMP" ); trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) ); if( BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_PCLASS ], 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: DEBUGNAME( "EV_LEV1_GRAB" ); trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL1Grab ); break; case EV_LEV4_CHARGE_PREPARE: DEBUGNAME( "EV_LEV4_CHARGE_PREPARE" ); trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL4ChargePrepare ); break; case EV_LEV4_CHARGE_START: DEBUGNAME( "EV_LEV4_CHARGE_START" ); //FIXME: stop cgs.media.alienL4ChargePrepare playing here trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL4ChargeStart ); 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; // // weapon events // case EV_NOAMMO: DEBUGNAME( "EV_NOAMMO" ); { } 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, WPM_PRIMARY ); break; case EV_FIRE_WEAPON2: DEBUGNAME( "EV_FIRE_WEAPON2" ); CG_FireWeapon( cent, WPM_SECONDARY ); break; case EV_FIRE_WEAPON3: DEBUGNAME( "EV_FIRE_WEAPON3" ); CG_FireWeapon( cent, WPM_TERTIARY ); break; //================================================================= // // other events // case EV_PLAYER_TELEPORT_IN: DEBUGNAME( "EV_PLAYER_TELEPORT_IN" ); //deprecated break; case EV_PLAYER_TELEPORT_OUT: DEBUGNAME( "EV_PLAYER_TELEPORT_OUT" ); CG_PlayerDisconnect( position ); break; case EV_BUILD_CONSTRUCT: DEBUGNAME( "EV_BUILD_CONSTRUCT" ); //do something useful here break; case EV_BUILD_DESTROY: DEBUGNAME( "EV_BUILD_DESTROY" ); //do something useful here break; case EV_RPTUSE_SOUND: DEBUGNAME( "EV_RPTUSE_SOUND" ); trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.repeaterUseSound ); break; case EV_GRENADE_BOUNCE: DEBUGNAME( "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; // // missile impacts // case EV_MISSILE_HIT: DEBUGNAME( "EV_MISSILE_HIT" ); ByteToDir( es->eventParm, dir ); CG_MissileHitPlayer( (weapon_t)es->weapon, (weaponMode_t)es->generic1, position, dir, es->otherEntityNum ); break; case EV_MISSILE_MISS: DEBUGNAME( "EV_MISSILE_MISS" ); ByteToDir( es->eventParm, dir ); CG_MissileHitWall( (weapon_t)es->weapon, (weaponMode_t)es->generic1, 0, position, dir, IMPACTSOUND_DEFAULT ); break; case EV_MISSILE_MISS_METAL: DEBUGNAME( "EV_MISSILE_MISS_METAL" ); ByteToDir( es->eventParm, dir ); CG_MissileHitWall( (weapon_t)es->weapon, (weaponMode_t)es->generic1, 0, position, dir, IMPACTSOUND_METAL ); break; case EV_HUMAN_BUILDABLE_EXPLOSION: DEBUGNAME( "EV_HUMAN_BUILDABLE_EXPLOSION" ); ByteToDir( es->eventParm, dir ); CG_HumanBuildableExplosion( position, dir ); break; case EV_ALIEN_BUILDABLE_EXPLOSION: DEBUGNAME( "EV_ALIEN_BUILDABLE_EXPLOSION" ); ByteToDir( es->eventParm, dir ); CG_AlienBuildableExplosion( position, dir ); break; case EV_TESLATRAIL: DEBUGNAME( "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: DEBUGNAME( "EV_BULLET_HIT_WALL" ); ByteToDir( es->eventParm, dir ); CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, false, ENTITYNUM_WORLD ); break; case EV_BULLET_HIT_FLESH: DEBUGNAME( "EV_BULLET_HIT_FLESH" ); CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, true, 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_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; case EV_GIB_PLAYER: DEBUGNAME( "EV_GIB_PLAYER" ); // no gibbing 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; case EV_BUILD_DELAY: DEBUGNAME( "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: DEBUGNAME( "EV_BUILD_REPAIR" ); trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.buildableRepairSound ); break; case EV_BUILD_REPAIRED: DEBUGNAME( "EV_BUILD_REPAIRED" ); trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.buildableRepairedSound ); break; case EV_OVERMIND_ATTACK: DEBUGNAME( "EV_OVERMIND_ATTACK" ); if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_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: DEBUGNAME( "EV_OVERMIND_DYING" ); if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_ALIENS ) { trap_S_StartLocalSound( cgs.media.alienOvermindDying, CHAN_ANNOUNCER ); CG_CenterPrint( "The Overmind is dying!", 200, GIANTCHAR_WIDTH * 4 ); } break; case EV_DCC_ATTACK: DEBUGNAME( "EV_DCC_ATTACK" ); if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS ) { //trap_S_StartLocalSound( cgs.media.humanDCCAttack, CHAN_ANNOUNCER ); CG_CenterPrint( "Our base is under attack!", 200, GIANTCHAR_WIDTH * 4 ); } break; case EV_OVERMIND_SPAWNS: DEBUGNAME( "EV_OVERMIND_SPAWNS" ); if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_ALIENS ) { trap_S_StartLocalSound( cgs.media.alienOvermindSpawns, CHAN_ANNOUNCER ); CG_CenterPrint( "The Overmind needs spawns!", 200, GIANTCHAR_WIDTH * 4 ); } break; case EV_ALIEN_EVOLVE: DEBUGNAME( "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: DEBUGNAME( "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: DEBUGNAME( "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: DEBUGNAME( "EV_MEDKIT_USED" ); trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.medkitUseSound ); break; case EV_PLAYER_RESPAWN: DEBUGNAME( "EV_PLAYER_RESPAWN" ); if( es->number == cg.clientNum ) cg.spawnTime = cg.time; break; default: DEBUGNAME( "UNKNOWN" ); CG_Error( "Unknown event: %i", event ); break; } }