/* * CG_Reset */ void CG_Reset( void ) { CG_ResetPModels(); CG_ResetKickAngles(); CG_ResetColorBlend(); CG_ResetDamageIndicator(); CG_ResetItemTimers(); CG_ClearDecals(); CG_ClearPolys(); CG_ClearEffects(); CG_ClearLocalEntities(); // start up announcer events queue from clean CG_ClearAnnouncerEvents(); cg.time = 0; cg.realTime = 0; // reset prediction optimization cg.predictFrom = 0; memset( cg_entities, 0, sizeof( cg_entities ) ); }
/* * 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; } }