/* * CG_ViewWeapon_StartAnimationEvent */ void CG_ViewWeapon_StartAnimationEvent( int newAnim ) { if( !cg.view.drawWeapon ) return; cg.weapon.eventAnim = newAnim; cg.weapon.eventAnimStartTime = cg.time; CG_ViewWeapon_RefreshAnimation( &cg.weapon ); }
/* * 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; } }
/* * CG_CalcViewWeapon */ void CG_CalcViewWeapon( cg_viewweapon_t *viewweapon ) { orientation_t tag; weaponinfo_t *weaponInfo; vec3_t gunAngles; vec3_t gunOffset; float fallfrac, fallkick; CG_ViewWeapon_RefreshAnimation( viewweapon ); //if( cg.view.thirdperson ) // return; weaponInfo = CG_GetWeaponInfo( viewweapon->weapon ); viewweapon->ent.model = weaponInfo->model[HAND]; viewweapon->ent.renderfx = RF_MINLIGHT|RF_WEAPONMODEL|RF_FORCENOLOD|(cg_shadows->integer < 2 ? RF_NOSHADOW : 0); viewweapon->ent.scale = 1.0f; viewweapon->ent.customShader = NULL; viewweapon->ent.customSkin = NULL; viewweapon->ent.rtype = RT_MODEL; Vector4Set( viewweapon->ent.shaderRGBA, 255, 255, 255, 255 ); // calculate the entity position #if 1 VectorCopy( cg.view.origin, viewweapon->ent.origin ); #else VectorCopy( cg.predictedPlayerState.pmove.origin, viewweapon->ent.origin ); viewweapon->ent.origin[2] += cg.predictedPlayerState.viewheight; #endif // weapon config offsets VectorAdd( weaponInfo->handpositionAngles, cg.predictedPlayerState.viewangles, gunAngles ); gunOffset[FORWARD] = cg_gunz->value + weaponInfo->handpositionOrigin[FORWARD]; gunOffset[RIGHT] = cg_gunx->value + weaponInfo->handpositionOrigin[RIGHT]; gunOffset[UP] = cg_guny->value + weaponInfo->handpositionOrigin[UP]; // hand cvar offset if( cgs.demoPlaying ) { if( hand->integer == 0 ) gunOffset[RIGHT] += cg_handOffset->value; else if( hand->integer == 1 ) gunOffset[RIGHT] -= cg_handOffset->value; } else { if( cgs.clientInfo[cg.view.POVent-1].hand == 0 ) gunOffset[RIGHT] += cg_handOffset->value; else if( cgs.clientInfo[cg.view.POVent-1].hand == 1 ) gunOffset[RIGHT] -= cg_handOffset->value; } // fallkick offset if( cg.weapon.fallEff_Time > cg.time ) { fallfrac = (float)( cg.time - cg.weapon.fallEff_rebTime ) / (float)( cg.weapon.fallEff_Time - cg.weapon.fallEff_rebTime ); fallkick = sin( DEG2RAD( fallfrac*180 ) ) * ( ( cg.weapon.fallEff_Time - cg.weapon.fallEff_rebTime ) * 0.01f ); } else { cg.weapon.fallEff_Time = cg.weapon.fallEff_rebTime = 0; fallkick = fallfrac = 0; } gunOffset[UP] -= fallkick; // apply the offsets #if 1 VectorMA( viewweapon->ent.origin, gunOffset[FORWARD], &cg.view.axis[AXIS_FORWARD], viewweapon->ent.origin ); VectorMA( viewweapon->ent.origin, gunOffset[RIGHT], &cg.view.axis[AXIS_RIGHT], viewweapon->ent.origin ); VectorMA( viewweapon->ent.origin, gunOffset[UP], &cg.view.axis[AXIS_UP], viewweapon->ent.origin ); #else Matrix3_FromAngles( cg.predictedPlayerState.viewangles, offsetAxis ); VectorMA( viewweapon->ent.origin, gunOffset[FORWARD], &offsetAxis[AXIS_FORWARD], viewweapon->ent.origin ); VectorMA( viewweapon->ent.origin, gunOffset[RIGHT], &offsetAxis[AXIS_RIGHT], viewweapon->ent.origin ); VectorMA( viewweapon->ent.origin, gunOffset[UP], &offsetAxis[AXIS_UP], viewweapon->ent.origin ); #endif // add angles effects CG_ViewWeapon_AddAngleEffects( gunAngles ); // finish AnglesToAxis( gunAngles, viewweapon->ent.axis ); if( cg_gun_fov->integer && !cg.predictedPlayerState.pmove.stats[PM_STAT_ZOOMTIME] ) { float gun_fov = bound( 20, cg_gun_fov->value, 160 ); float fracWeapFOV = ( 1.0f / cg.view.fracDistFOV ) * tan( gun_fov * ( M_PI/180 ) * 0.5f ); VectorScale( &viewweapon->ent.axis[AXIS_FORWARD], fracWeapFOV, &viewweapon->ent.axis[AXIS_FORWARD] ); } // if the player doesn't want to view the weapon we still have to build the projection source if( CG_GrabTag( &tag, &viewweapon->ent, "tag_weapon" ) ) CG_ViewWeapon_UpdateProjectionSource( viewweapon->ent.origin, viewweapon->ent.axis, tag.origin, tag.axis ); else CG_ViewWeapon_UpdateProjectionSource( viewweapon->ent.origin, viewweapon->ent.axis, vec3_origin, axis_identity ); }