/* =============== CG_OffsetFirstPersonView =============== */ void CG_OffsetFirstPersonView( void ) { float *origin; float *angles; float bob; float ratio; float delta; float speed; float f; vec3_t predictedVelocity; int timeDelta; float bob2; vec3_t normal, baseOrigin; playerState_t *ps = &cg.predictedPlayerState; BG_GetClientNormal( ps, normal ); if( cg.snap->ps.pm_type == PM_INTERMISSION ) return; origin = cg.refdef.vieworg; angles = cg.refdefViewAngles; VectorCopy( origin, baseOrigin ); // if dead, fix the angle and don't add any kick if( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 ) { angles[ ROLL ] = 40; angles[ PITCH ] = -15; angles[ YAW ] = cg.snap->ps.stats[ STAT_VIEWLOCK ]; origin[ 2 ] += cg.predictedPlayerState.viewheight; return; } // camera shake effect else if( cg.snap->ps.stats[ STAT_SHAKE ] > 0 ) { float fac; fac = (float) cg.snap->ps.stats[ STAT_SHAKE ] * cg_cameraShakeMagnitude.value * 0.15f; angles[ 0 ] += crandom() * fac; angles[ 1 ] += crandom() * fac; angles[ 2 ] += crandom() * fac; } // add angles based on damage kick if( cg.damageTime ) { ratio = cg.time - cg.damageTime; if( ratio < DAMAGE_DEFLECT_TIME ) { ratio /= DAMAGE_DEFLECT_TIME; angles[ PITCH ] += ratio * cg.v_dmg_pitch; angles[ ROLL ] += ratio * cg.v_dmg_roll; } else { ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME; if( ratio > 0 ) { angles[ PITCH ] += ratio * cg.v_dmg_pitch; angles[ ROLL ] += ratio * cg.v_dmg_roll; } } } // add pitch based on fall kick #if 0 ratio = ( cg.time - cg.landTime) / FALL_TIME; if (ratio < 0) ratio = 0; angles[PITCH] += ratio * cg.fall_value; #endif // add angles based on velocity VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity ); delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 0 ] ); angles[ PITCH ] += delta * cg_runpitch.value; delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 1 ] ); angles[ ROLL ] -= delta * cg_runroll.value; // add angles based on bob // bob amount is class dependant if( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT ) bob2 = 0.0f; else bob2 = BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->bob; #define LEVEL4_FEEDBACK 10.0f //give a charging player some feedback if( ps->weapon == WP_ALEVEL4 ) { if( ps->stats[ STAT_MISC ] > 0 ) { float fraction = (float)ps->stats[ STAT_MISC ] / LEVEL4_TRAMPLE_CHARGE_MAX; if( fraction > 1.0f ) fraction = 1.0f; bob2 *= ( 1.0f + fraction * LEVEL4_FEEDBACK ); } } if( bob2 != 0.0f ) { // make sure the bob is visible even at low speeds speed = cg.xyspeed > 200 ? cg.xyspeed : 200; delta = cg.bobfracsin * ( bob2 ) * speed; if( cg.predictedPlayerState.pm_flags & PMF_DUCKED ) delta *= 3; // crouching angles[ PITCH ] += delta; delta = cg.bobfracsin * ( bob2 ) * speed; if( cg.predictedPlayerState.pm_flags & PMF_DUCKED ) delta *= 3; // crouching accentuates roll if( cg.bobcycle & 1 ) delta = -delta; angles[ ROLL ] += delta; } #define LEVEL3_FEEDBACK 20.0f //provide some feedback for pouncing if( ( cg.predictedPlayerState.weapon == WP_ALEVEL3 || cg.predictedPlayerState.weapon == WP_ALEVEL3_UPG ) && cg.predictedPlayerState.stats[ STAT_MISC ] > 0 ) { float fraction1, fraction2; vec3_t forward; AngleVectors( angles, forward, NULL, NULL ); VectorNormalize( forward ); fraction1 = (float)cg.predictedPlayerState.stats[ STAT_MISC ] / LEVEL3_POUNCE_TIME_UPG; if( fraction1 > 1.0f ) fraction1 = 1.0f; fraction2 = -sin( fraction1 * M_PI / 2 ); VectorMA( origin, LEVEL3_FEEDBACK * fraction2, forward, origin ); } #define STRUGGLE_DIST 5.0f #define STRUGGLE_TIME 250 //allow the player to struggle a little whilst grabbed if( cg.predictedPlayerState.pm_type == PM_GRABBED ) { vec3_t forward, right, up; usercmd_t cmd; int cmdNum; float fFraction, rFraction, uFraction; float fFraction2, rFraction2, uFraction2; cmdNum = trap_GetCurrentCmdNumber(); trap_GetUserCmd( cmdNum, &cmd ); AngleVectors( angles, forward, right, up ); fFraction = (float)( cg.time - cg.forwardMoveTime ) / STRUGGLE_TIME; rFraction = (float)( cg.time - cg.rightMoveTime ) / STRUGGLE_TIME; uFraction = (float)( cg.time - cg.upMoveTime ) / STRUGGLE_TIME; if( fFraction > 1.0f ) fFraction = 1.0f; if( rFraction > 1.0f ) rFraction = 1.0f; if( uFraction > 1.0f ) uFraction = 1.0f; fFraction2 = -sin( fFraction * M_PI / 2 ); rFraction2 = -sin( rFraction * M_PI / 2 ); uFraction2 = -sin( uFraction * M_PI / 2 ); if( cmd.forwardmove > 0 ) VectorMA( origin, STRUGGLE_DIST * fFraction, forward, origin ); else if( cmd.forwardmove < 0 ) VectorMA( origin, -STRUGGLE_DIST * fFraction, forward, origin ); else cg.forwardMoveTime = cg.time; if( cmd.rightmove > 0 ) VectorMA( origin, STRUGGLE_DIST * rFraction, right, origin ); else if( cmd.rightmove < 0 ) VectorMA( origin, -STRUGGLE_DIST * rFraction, right, origin ); else cg.rightMoveTime = cg.time; if( cmd.upmove > 0 ) VectorMA( origin, STRUGGLE_DIST * uFraction, up, origin ); else if( cmd.upmove < 0 ) VectorMA( origin, -STRUGGLE_DIST * uFraction, up, origin ); else cg.upMoveTime = cg.time; } if( ( cg.predictedPlayerEntity.currentState.eFlags & EF_POISONCLOUDED ) && ( cg.time - cg.poisonedTime < PCLOUD_DISORIENT_DURATION) && !( cg.snap->ps.pm_flags & PMF_FOLLOW ) ) { float scale, fraction, pitchFraction; scale = 1.0f - (float)( cg.time - cg.poisonedTime ) / BG_PlayerPoisonCloudTime( &cg.predictedPlayerState ); if( scale < 0.0f ) scale = 0.0f; fraction = sin( ( cg.time - cg.poisonedTime ) / 500.0f * M_PI * PCLOUD_ROLL_FREQUENCY ) * scale; pitchFraction = sin( ( cg.time - cg.poisonedTime ) / 200.0f * M_PI * PCLOUD_ROLL_FREQUENCY ) * scale; angles[ ROLL ] += fraction * PCLOUD_ROLL_AMPLITUDE; angles[ YAW ] += fraction * PCLOUD_ROLL_AMPLITUDE; angles[ PITCH ] += pitchFraction * PCLOUD_ROLL_AMPLITUDE / 2.0f; } // this *feels* more realisitic for humans if( cg.predictedPlayerState.stats[ STAT_TEAM ] == TEAM_HUMANS && ( cg.predictedPlayerState.pm_type == PM_NORMAL || cg.predictedPlayerState.pm_type == PM_JETPACK ) ) { angles[PITCH] += cg.bobfracsin * bob2 * 0.5; // heavy breathing effects //FIXME: sound if( cg.predictedPlayerState.stats[ STAT_STAMINA ] < STAMINA_BREATHING_LEVEL ) { float deltaBreath = ( cg.predictedPlayerState.stats[ STAT_STAMINA ] - STAMINA_BREATHING_LEVEL ) / -250.0; float deltaAngle = cos( (float)cg.time/150.0 ) * deltaBreath; deltaAngle += ( deltaAngle < 0 ? -deltaAngle : deltaAngle ) * 0.5; angles[ PITCH ] -= deltaAngle; } } //=================================== // add view height VectorMA( origin, ps->viewheight, normal, origin ); // smooth out duck height changes timeDelta = cg.time - cg.duckTime; if( timeDelta < DUCK_TIME) { cg.refdef.vieworg[ 2 ] -= cg.duckChange * ( DUCK_TIME - timeDelta ) / DUCK_TIME; } // add bob height bob = cg.bobfracsin * cg.xyspeed * bob2; if( bob > 6 ) bob = 6; VectorMA( origin, bob, normal, origin ); // add fall height delta = cg.time - cg.landTime; if( delta < LAND_DEFLECT_TIME ) { f = delta / LAND_DEFLECT_TIME; cg.refdef.vieworg[ 2 ] += cg.landChange * f; } else if( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) { delta -= LAND_DEFLECT_TIME; f = 1.0 - ( delta / LAND_RETURN_TIME ); cg.refdef.vieworg[ 2 ] += cg.landChange * f; } // add step offset CG_StepOffset( ); }
/* =============== CG_OffsetFirstPersonView =============== */ void CG_OffsetFirstPersonView( void ) { float *origin; float *angles; float bob; float ratio; float delta; float speed; float f; vec3_t predictedVelocity; int timeDelta; float bob2; vec3_t normal, baseOrigin; playerState_t *ps = &cg.predictedPlayerState; BG_GetClientNormal( ps, normal ); if ( cg.snap->ps.pm_type == PM_INTERMISSION ) { return; } origin = cg.refdef.vieworg; angles = cg.refdefViewAngles; VectorCopy( origin, baseOrigin ); // if dead, fix the angle and don't add any kick if ( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 ) { angles[ ROLL ] = 40; angles[ PITCH ] = -15; angles[ YAW ] = cg.snap->ps.stats[ STAT_VIEWLOCK ]; origin[ 2 ] += cg.predictedPlayerState.viewheight; return; } // add angles based on damage kick if ( cg.damageTime ) { ratio = cg.time - cg.damageTime; if ( ratio < DAMAGE_DEFLECT_TIME ) { ratio /= DAMAGE_DEFLECT_TIME; angles[ PITCH ] += ratio * cg.v_dmg_pitch; angles[ ROLL ] += ratio * cg.v_dmg_roll; } else { ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME; if ( ratio > 0 ) { angles[ PITCH ] += ratio * cg.v_dmg_pitch; angles[ ROLL ] += ratio * cg.v_dmg_roll; } } } // add pitch based on fall kick #if 0 ratio = ( cg.time - cg.landTime ) / FALL_TIME; if ( ratio < 0 ) { ratio = 0; } angles[ PITCH ] += ratio * cg.fall_value; #endif // add angles based on velocity VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity ); delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 0 ] ); angles[ PITCH ] += delta * cg_runpitch.value; delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 1 ] ); angles[ ROLL ] -= delta * cg_runroll.value; // add angles based on bob // bob amount is class-dependent if ( cg.snap->ps.persistant[ PERS_SPECSTATE ] != SPECTATOR_NOT ) { bob2 = 0.0f; } else { bob2 = BG_Class( cg.predictedPlayerState.stats[ STAT_CLASS ] )->bob; } #define LEVEL4_FEEDBACK 10.0f //give a charging player some feedback if ( ps->weapon == WP_ALEVEL4 ) { if ( ps->stats[ STAT_MISC ] > 0 ) { float fraction = ( float ) ps->stats[ STAT_MISC ] / LEVEL4_TRAMPLE_CHARGE_MAX; if ( fraction > 1.0f ) { fraction = 1.0f; } bob2 *= ( 1.0f + fraction * LEVEL4_FEEDBACK ); } } if ( bob2 != 0.0f ) { // make sure the bob is visible even at low speeds speed = cg.xyspeed > 200 ? cg.xyspeed : 200; delta = cg.bobfracsin * ( bob2 ) * speed; if ( cg.predictedPlayerState.pm_flags & PMF_DUCKED ) { delta *= 3; // crouching } angles[ PITCH ] += delta; delta = cg.bobfracsin * ( bob2 ) * speed; if ( cg.predictedPlayerState.pm_flags & PMF_DUCKED ) { delta *= 3; // crouching accentuates roll } if ( cg.bobcycle & 1 ) { delta = -delta; } angles[ ROLL ] += delta; } #define LEVEL3_FEEDBACK 20.0f //provide some feedback for pouncing if ( ( cg.predictedPlayerState.weapon == WP_ALEVEL3 || cg.predictedPlayerState.weapon == WP_ALEVEL3_UPG ) && cg.predictedPlayerState.stats[ STAT_MISC ] > 0 ) { float fraction1, fraction2; vec3_t forward; AngleVectors( angles, forward, NULL, NULL ); VectorNormalize( forward ); fraction1 = ( float ) cg.predictedPlayerState.stats[ STAT_MISC ] / LEVEL3_POUNCE_TIME_UPG; if ( fraction1 > 1.0f ) { fraction1 = 1.0f; } fraction2 = -sin( fraction1 * M_PI / 2 ); VectorMA( origin, LEVEL3_FEEDBACK * fraction2, forward, origin ); } #define STRUGGLE_DIST 5.0f #define STRUGGLE_TIME 250 //allow the player to struggle a little whilst grabbed if ( cg.predictedPlayerState.pm_type == PM_GRABBED ) { vec3_t forward, right, up; usercmd_t cmd; int cmdNum; float fFraction, rFraction, uFraction; cmdNum = trap_GetCurrentCmdNumber(); trap_GetUserCmd( cmdNum, &cmd ); AngleVectors( angles, forward, right, up ); fFraction = ( float )( cg.time - cg.forwardMoveTime ) / STRUGGLE_TIME; rFraction = ( float )( cg.time - cg.rightMoveTime ) / STRUGGLE_TIME; uFraction = ( float )( cg.time - cg.upMoveTime ) / STRUGGLE_TIME; if ( fFraction > 1.0f ) { fFraction = 1.0f; } if ( rFraction > 1.0f ) { rFraction = 1.0f; } if ( uFraction > 1.0f ) { uFraction = 1.0f; } if ( cmd.forwardmove > 0 ) { VectorMA( origin, STRUGGLE_DIST * fFraction, forward, origin ); } else if ( cmd.forwardmove < 0 ) { VectorMA( origin, -STRUGGLE_DIST * fFraction, forward, origin ); } else { cg.forwardMoveTime = cg.time; } if ( cmd.rightmove > 0 ) { VectorMA( origin, STRUGGLE_DIST * rFraction, right, origin ); } else if ( cmd.rightmove < 0 ) { VectorMA( origin, -STRUGGLE_DIST * rFraction, right, origin ); } else { cg.rightMoveTime = cg.time; } if ( cmd.upmove > 0 ) { VectorMA( origin, STRUGGLE_DIST * uFraction, up, origin ); } else if ( cmd.upmove < 0 ) { VectorMA( origin, -STRUGGLE_DIST * uFraction, up, origin ); } else { cg.upMoveTime = cg.time; } } // this *feels* more realisitic for humans <- this comment feels very descriptive if ( cg.predictedPlayerState.persistant[ PERS_TEAM ] == TEAM_HUMANS && cg.predictedPlayerState.pm_type == PM_NORMAL ) { angles[ PITCH ] += cg.bobfracsin * bob2 * 0.5; } // add view height VectorMA( origin, ps->viewheight, normal, origin ); // smooth out duck height changes timeDelta = cg.time - cg.duckTime; if ( timeDelta < DUCK_TIME ) { cg.refdef.vieworg[ 2 ] -= cg.duckChange * ( DUCK_TIME - timeDelta ) / DUCK_TIME; } // add bob height bob = cg.bobfracsin * cg.xyspeed * bob2; if ( bob > 6 ) { bob = 6; } VectorMA( origin, bob, normal, origin ); // add fall height delta = cg.time - cg.landTime; if ( delta < LAND_DEFLECT_TIME ) { f = delta / LAND_DEFLECT_TIME; cg.refdef.vieworg[ 2 ] += cg.landChange * f; } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) { delta -= LAND_DEFLECT_TIME; f = 1.0 - ( delta / LAND_RETURN_TIME ); cg.refdef.vieworg[ 2 ] += cg.landChange * f; } // add step offset CG_StepOffset(); }
/* =============== CG_OffsetFirstPersonView =============== */ static void CG_OffsetFirstPersonView( void ) { float *origin; float *angles; float bob; float ratio; float delta; float speed; float f; vec3_t predictedVelocity; int timeDelta; if ( cg.snap->ps.pm_type == PM_INTERMISSION ) { return; } origin = cg.refdef.vieworg; angles = cg.refdefViewAngles; // if dead, fix the angle and don't add any kick if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) { angles[ROLL] = 40; angles[PITCH] = -15; angles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW]; origin[2] += cg.predictedPlayerState.viewheight; return; } // add angles based on weapon kick VectorAdd (angles, cg.kick_angles, angles); // add angles based on damage kick if ( cg.damageTime ) { ratio = cg.time - cg.damageTime; if ( ratio < DAMAGE_DEFLECT_TIME ) { ratio /= DAMAGE_DEFLECT_TIME; angles[PITCH] += ratio * cg.v_dmg_pitch; angles[ROLL] += ratio * cg.v_dmg_roll; } else { ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME; if ( ratio > 0 ) { angles[PITCH] += ratio * cg.v_dmg_pitch; angles[ROLL] += ratio * cg.v_dmg_roll; } } } // add pitch based on fall kick #if 0 ratio = ( cg.time - cg.landTime) / FALL_TIME; if (ratio < 0) ratio = 0; angles[PITCH] += ratio * cg.fall_value; #endif // add angles based on velocity VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity ); delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[0]); angles[PITCH] += delta * cg_runpitch.value; delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[1]); angles[ROLL] -= delta * cg_runroll.value; // add angles based on bob // make sure the bob is visible even at low speeds speed = cg.xyspeed > 200 ? cg.xyspeed : 200; delta = cg.bobfracsin * cg_bobpitch.value * speed; if (cg.predictedPlayerState.pm_flags & PMF_DUCKED) delta *= 3; // crouching angles[PITCH] += delta; delta = cg.bobfracsin * cg_bobroll.value * speed; if (cg.predictedPlayerState.pm_flags & PMF_DUCKED) delta *= 3; // crouching accentuates roll if (cg.bobcycle & 1) delta = -delta; angles[ROLL] += delta; //=================================== // add view height origin[2] += cg.predictedPlayerState.viewheight; // smooth out duck height changes timeDelta = cg.time - cg.duckTime; if ( timeDelta < DUCK_TIME) { cg.refdef.vieworg[2] -= cg.duckChange * (DUCK_TIME - timeDelta) / DUCK_TIME; } // add bob height bob = cg.bobfracsin * cg.xyspeed * cg_bobup.value; if (bob > 6) { bob = 6; } origin[2] += bob; // add fall height delta = cg.time - cg.landTime; if ( delta < LAND_DEFLECT_TIME ) { f = delta / LAND_DEFLECT_TIME; cg.refdef.vieworg[2] += cg.landChange * f; } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) { delta -= LAND_DEFLECT_TIME; f = 1.0 - ( delta / LAND_RETURN_TIME ); cg.refdef.vieworg[2] += cg.landChange * f; } // add step offset CG_StepOffset(); // add kick offset VectorAdd (origin, cg.kick_origin, origin); // pivot the eye based on a neck length #if 0 { #define NECK_LENGTH 8 vec3_t forward, up; cg.refdef.vieworg[2] -= NECK_LENGTH; AngleVectors( cg.refdefViewAngles, forward, NULL, up ); VectorMA( cg.refdef.vieworg, 3, forward, cg.refdef.vieworg ); VectorMA( cg.refdef.vieworg, NECK_LENGTH, up, cg.refdef.vieworg ); } #endif }
static void CG_OffsetThirdPersonView( void ) { vec3_t forward, right, up; vec3_t view; vec3_t focusAngles; trace_t trace; static vec3_t mins = { -5, -5, -5 }; static vec3_t maxs = { 5, 5, 5 }; vec3_t focusPoint; float focusDist; float forwardScale, sideScale; float thirdPersonAngle, thirdPersonRange; cg.refdef.vieworg[2] += cg.cur_lc->predictedPlayerState.viewheight; VectorCopy( cg.refdefViewAngles, focusAngles ); if ( cg.cur_lc->cameraOrbit ) { thirdPersonAngle = cg.cur_lc->cameraOrbitAngle; thirdPersonRange = cg.cur_lc->cameraOrbitRange; // make camera orbit horizontal focusAngles[PITCH] = 0; cg.refdefViewAngles[PITCH] = 0; } else { thirdPersonAngle = cg_thirdPersonAngle[cg.cur_localPlayerNum].value; thirdPersonRange = cg_thirdPersonRange[cg.cur_localPlayerNum].value; // if dead, look at killer if ( cg.cur_lc->predictedPlayerState.stats[STAT_HEALTH] <= 0 ) { focusAngles[YAW] = cg.cur_lc->predictedPlayerState.stats[STAT_DEAD_YAW]; cg.refdefViewAngles[YAW] = cg.cur_lc->predictedPlayerState.stats[STAT_DEAD_YAW]; } } if ( focusAngles[PITCH] > 45 ) { focusAngles[PITCH] = 45; // don't go too far overhead } AngleVectors( focusAngles, forward, NULL, NULL ); if ( cg_thirdPersonSmooth[cg.cur_localPlayerNum].integer ) { CG_StepOffset( cg.refdef.vieworg ); } VectorMA( cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint ); VectorCopy( cg.refdef.vieworg, view ); view[2] += cg_thirdPersonHeight[cg.cur_localPlayerNum].value; cg.refdefViewAngles[PITCH] *= 0.5; AngleVectors( cg.refdefViewAngles, forward, right, up ); forwardScale = cos( thirdPersonAngle / 180 * M_PI ); sideScale = sin( thirdPersonAngle / 180 * M_PI ); VectorMA( view, -thirdPersonRange * forwardScale, forward, view ); VectorMA( view, -thirdPersonRange * sideScale, right, view ); // trace a ray from the origin to the viewpoint to make sure the view isn't // in a solid block. Use a 10 by 10 block to prevent the view from near clipping anything if (!cg_cameraMode.integer) { CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.cur_lc->predictedPlayerState.playerNum, MASK_SOLID ); if ( trace.fraction != 1.0 ) { VectorCopy( trace.endpos, view ); view[2] += (1.0 - trace.fraction) * 32; // try another trace to this position, because a tunnel may have the ceiling // close enough that this is poking out CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.cur_lc->predictedPlayerState.playerNum, MASK_SOLID ); VectorCopy( trace.endpos, view ); } } VectorCopy( view, cg.refdef.vieworg ); // select pitch to look at focus point from vieword VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint ); focusDist = sqrt( focusPoint[0] * focusPoint[0] + focusPoint[1] * focusPoint[1] ); if ( focusDist < 1 ) { focusDist = 1; // should never happen } cg.refdefViewAngles[PITCH] = -180 / M_PI * atan2( focusPoint[2], focusDist ); cg.refdefViewAngles[YAW] -= thirdPersonAngle; }
/* =============== CG_OffsetFirstPersonView =============== */ static void CG_OffsetFirstPersonView( void ) { float *origin; float *angles; float bob; float ratio; float delta; float speed; float f; vec3_t predictedVelocity; char temp[1024]; vec3_t org; vec3_t axis[3]; vec3_t ang; int timeDelta; float bob2; vec3_t normal, baseOrigin; 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 ); if( cg.snap->ps.pm_type == PM_INTERMISSION ) return; origin = cg.refdef.vieworg; angles = cg.refdefViewAngles; VectorCopy( origin, baseOrigin ); // if dead, fix the angle and don't add any kick if( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 ) { angles[ ROLL ] = 40; angles[ PITCH ] = -15; angles[ YAW ] = cg.snap->ps.stats[ STAT_VIEWLOCK ]; origin[ 2 ] += cg.predictedPlayerState.viewheight; return; } // add angles based on weapon kick VectorAdd( angles, cg.kick_angles, angles ); // add angles based on damage kick if( cg.damageTime ) { ratio = cg.time - cg.damageTime; if( ratio < DAMAGE_DEFLECT_TIME ) { ratio /= DAMAGE_DEFLECT_TIME; angles[ PITCH ] += ratio * cg.v_dmg_pitch; angles[ ROLL ] += ratio * cg.v_dmg_roll; } else { ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME; if( ratio > 0 ) { angles[ PITCH ] += ratio * cg.v_dmg_pitch; angles[ ROLL ] += ratio * cg.v_dmg_roll; } } } // add pitch based on fall kick #if 0 ratio = ( cg.time - cg.landTime) / FALL_TIME; if (ratio < 0) ratio = 0; angles[PITCH] += ratio * cg.fall_value; #endif // add angles based on velocity VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity ); delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 0 ] ); angles[ PITCH ] += delta * cg_runpitch.value; delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 1 ] ); angles[ ROLL ] -= delta * cg_runroll.value; // add angles based on bob //TA: bob amount is class dependant if( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) bob2 = 0.0f; else bob2 = BG_FindBobForClass( cg.predictedPlayerState.stats[ STAT_PCLASS ] ); #define LEVEL4_FEEDBACK 10.0f //give a charging player some feedback if( ps->weapon == WP_ALEVEL4 ) { if( ps->stats[ STAT_MISC ] > 0 ) { float fraction = (float)ps->stats[ STAT_MISC ] / (float)LEVEL4_CHARGE_TIME; if( fraction > 1.0f ) fraction = 1.0f; bob2 *= ( 1.0f + fraction * LEVEL4_FEEDBACK ); } } if( bob2 != 0.0f ) { // make sure the bob is visible even at low speeds speed = cg.xyspeed > 200 ? cg.xyspeed : 200; delta = cg.bobfracsin * ( bob2 ) * speed; if( cg.predictedPlayerState.pm_flags & PMF_DUCKED ) delta *= 3; // crouching angles[ PITCH ] += delta; delta = cg.bobfracsin * ( bob2 ) * speed; if( cg.predictedPlayerState.pm_flags & PMF_DUCKED ) delta *= 3; // crouching accentuates roll if( cg.bobcycle & 1 ) delta = -delta; angles[ ROLL ] += delta; } #define LEVEL3_FEEDBACK 20.0f //provide some feedback for pouncing if( cg.predictedPlayerState.weapon == WP_ALEVEL3 || cg.predictedPlayerState.weapon == WP_ALEVEL3_UPG ) { if( cg.predictedPlayerState.stats[ STAT_MISC ] > 0 ) { float fraction1, fraction2; vec3_t forward; AngleVectors( angles, forward, NULL, NULL ); VectorNormalize( forward ); fraction1 = (float)( cg.time - cg.weapon2Time ) / (float)LEVEL3_POUNCE_CHARGE_TIME; if( fraction1 > 1.0f ) fraction1 = 1.0f; fraction2 = -sin( fraction1 * M_PI / 2 ); VectorMA( origin, LEVEL3_FEEDBACK * fraction2, forward, origin ); } } #define STRUGGLE_DIST 5.0f #define STRUGGLE_TIME 250 //allow the player to struggle a little whilst grabbed if( cg.predictedPlayerState.pm_type == PM_GRABBED ) { vec3_t forward, right, up; usercmd_t cmd; int cmdNum; float fFraction, rFraction, uFraction; float fFraction2, rFraction2, uFraction2; cmdNum = trap_GetCurrentCmdNumber(); trap_GetUserCmd( cmdNum, &cmd ); AngleVectors( angles, forward, right, up ); fFraction = (float)( cg.time - cg.forwardMoveTime ) / STRUGGLE_TIME; rFraction = (float)( cg.time - cg.rightMoveTime ) / STRUGGLE_TIME; uFraction = (float)( cg.time - cg.upMoveTime ) / STRUGGLE_TIME; if( fFraction > 1.0f ) fFraction = 1.0f; if( rFraction > 1.0f ) rFraction = 1.0f; if( uFraction > 1.0f ) uFraction = 1.0f; fFraction2 = -sin( fFraction * M_PI / 2 ); rFraction2 = -sin( rFraction * M_PI / 2 ); uFraction2 = -sin( uFraction * M_PI / 2 ); if( cmd.forwardmove > 0 ) VectorMA( origin, STRUGGLE_DIST * fFraction, forward, origin ); else if( cmd.forwardmove < 0 ) VectorMA( origin, -STRUGGLE_DIST * fFraction, forward, origin ); else cg.forwardMoveTime = cg.time; if( cmd.rightmove > 0 ) VectorMA( origin, STRUGGLE_DIST * rFraction, right, origin ); else if( cmd.rightmove < 0 ) VectorMA( origin, -STRUGGLE_DIST * rFraction, right, origin ); else cg.rightMoveTime = cg.time; if( cmd.upmove > 0 ) VectorMA( origin, STRUGGLE_DIST * uFraction, up, origin ); else if( cmd.upmove < 0 ) VectorMA( origin, -STRUGGLE_DIST * uFraction, up, origin ); else cg.upMoveTime = cg.time; } if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_POISONCLOUDED && !( cg.snap->ps.pm_flags & PMF_FOLLOW ) ) { float fraction = sin( ( (float)cg.time / 1000.0f ) * M_PI * 2 * PCLOUD_ROLL_FREQUENCY ); float pitchFraction = sin( ( (float)cg.time / 1000.0f ) * M_PI * 5 * PCLOUD_ROLL_FREQUENCY ); fraction *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME ); pitchFraction *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME ); angles[ ROLL ] += fraction * PCLOUD_ROLL_AMPLITUDE; angles[ YAW ] += fraction * PCLOUD_ROLL_AMPLITUDE; angles[ PITCH ] += pitchFraction * PCLOUD_ROLL_AMPLITUDE / 2.0f; } //TA: this *feels* more realisitic for humans if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS ) { angles[PITCH] += cg.bobfracsin * bob2 * 0.5; //TA: heavy breathing effects //FIXME: sound if( cg.predictedPlayerState.stats[ STAT_STAMINA ] < 0 ) { float deltaBreath = (float)( cg.predictedPlayerState.stats[ STAT_STAMINA ] < 0 ? -cg.predictedPlayerState.stats[ STAT_STAMINA ] : cg.predictedPlayerState.stats[ STAT_STAMINA ] ) / 200.0; float deltaAngle = cos( (float)cg.time/150.0 ) * deltaBreath; deltaAngle += ( deltaAngle < 0 ? -deltaAngle : deltaAngle ) * 0.5; angles[ PITCH ] -= deltaAngle; } } //=================================== // add view height //TA: when wall climbing the viewheight is not straight up if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING ) VectorMA( origin, ps->viewheight, normal, origin ); else origin[ 2 ] += cg.predictedPlayerState.viewheight; // smooth out duck height changes timeDelta = cg.time - cg.duckTime; if( timeDelta < DUCK_TIME) { cg.refdef.vieworg[ 2 ] -= cg.duckChange * ( DUCK_TIME - timeDelta ) / DUCK_TIME; } // add bob height bob = cg.bobfracsin * cg.xyspeed * bob2; if( bob > 6 ) bob = 6; //TA: likewise for bob if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING ) VectorMA( origin, bob, normal, origin ); else origin[ 2 ] += bob; // add fall height delta = cg.time - cg.landTime; if( delta < LAND_DEFLECT_TIME ) { f = delta / LAND_DEFLECT_TIME; cg.refdef.vieworg[ 2 ] += cg.landChange * f; } else if( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) { delta -= LAND_DEFLECT_TIME; f = 1.0 - ( delta / LAND_RETURN_TIME ); cg.refdef.vieworg[ 2 ] += cg.landChange * f; } // add step offset CG_StepOffset( ); // add kick offset VectorAdd (origin, cg.kick_origin, origin); }
/* =============== CG_OffsetFirstPersonView =============== */ static void CG_OffsetFirstPersonView( void ) { float *origin; float *angles; float bob; float ratio; float delta; float speed; float f; vec3_t predictedVelocity; int timeDelta; int land_deflect_time = LAND_DEFLECT_TIME; int land_return_time = LAND_RETURN_TIME; int shoot_deflect_time = LAND_DEFLECT_TIME - 50; if ( cg.snap->ps.pm_type == PM_INTERMISSION ) { return; } origin = cg.refdef.vieworg; angles = cg.refdefViewAngles; // add view height origin[2] += cg.predictedPlayerState.viewheight; // pivot the eye based on a neck length, new system by spoon if(cg.snap->ps.persistant[PERS_TEAM] < TEAM_SPECTATOR) { BG_ModifyEyeAngles( origin, angles, CG_Trace, cg.legOffset, qfalse); } // add angles based on weapon kick VectorAdd (angles, cg.kick_angles, angles); // add angles based on damage kick if ( cg.damageTime ) { ratio = cg.time - cg.damageTime; if ( ratio < DAMAGE_DEFLECT_TIME ) { ratio /= DAMAGE_DEFLECT_TIME; angles[PITCH] += ratio * cg.v_dmg_pitch; angles[ROLL] += ratio * cg.v_dmg_roll; } else { ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME; if ( ratio > 0 ) { angles[PITCH] += ratio * cg.v_dmg_pitch; angles[ROLL] += ratio * cg.v_dmg_roll; } } } // add pitch based on fall kick #if 0 ratio = ( cg.time - cg.landTime) / FALL_TIME; if (ratio < 0) ratio = 0; angles[PITCH] += ratio * cg.fall_value; #endif // add angles based on velocity VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity ); delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[0]); angles[PITCH] += delta * cg_runpitch.value; delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[1]); angles[ROLL] -= delta * cg_runroll.value; // add angles based on bob // make sure the bob is visible even at low speeds speed = cg.xyspeed > 200 ? cg.xyspeed : 200; delta = cg.bobfracsin * cg_bobpitch.value * speed; if (cg.predictedPlayerState.pm_flags & PMF_DUCKED) delta *= 3; // crouching angles[PITCH] += delta; delta = cg.bobfracsin * cg_bobroll.value * speed; if (cg.predictedPlayerState.pm_flags & PMF_DUCKED) delta *= 3; // crouching accentuates roll if (cg.bobcycle & 1) delta = -delta; angles[ROLL] += delta; //=================================== // smooth out duck height changes timeDelta = cg.time - cg.duckTime; if ( timeDelta < DUCK_TIME) { cg.refdef.vieworg[2] -= cg.duckChange * (DUCK_TIME - timeDelta) / DUCK_TIME; } // add bob height bob = cg.bobfracsin * cg.xyspeed * cg_bobup.value; if (bob > 6) { bob = 6; } origin[2] += bob; cg.legOffset[2] += bob; //check for bullethit if(!cg.landChange && cg.landAngleChange) { land_deflect_time /= 2; land_return_time /= 2; } // add fall height delta = cg.time - cg.landTime; if ( delta < land_deflect_time ) { f = delta / land_deflect_time; cg.refdef.vieworg[2] += cg.landChange * f; //anglechange cg.refdefViewAngles[ROLL] += cg.landAngleChange *f; } else if ( delta < land_deflect_time + land_return_time ) { delta -= land_deflect_time; f = 1.0 - ( delta / land_return_time ); cg.refdef.vieworg[2] += cg.landChange * f; //anglechange cg.refdefViewAngles[ROLL] += cg.landAngleChange *f; } // add shoot height delta = cg.time - cg.shootTime; if ( delta < shoot_deflect_time ) { f = delta / shoot_deflect_time; cg.refdef.vieworg[2] += cg.shootChange * f; //anglechange cg.refdefViewAngles[PITCH] -= cg.shootAngleChange *f; } else if ( delta < shoot_deflect_time + land_return_time ) { delta -= shoot_deflect_time; f = 1.0 - ( delta / land_return_time ); cg.refdef.vieworg[2] += cg.shootChange * f; //anglechange cg.refdefViewAngles[PITCH] -= cg.shootAngleChange *f; } // add step offset CG_StepOffset(); // add kick offset VectorAdd (origin, cg.kick_origin, origin); // pivot the eye based on a neck length #if 0 { #define NECK_LENGTH 8 vec3_t forward, up; cg.refdef.vieworg[2] -= NECK_LENGTH; AngleVectors( cg.refdefViewAngles, forward, NULL, up ); VectorMA( cg.refdef.vieworg, 3, forward, cg.refdef.vieworg ); VectorMA( cg.refdef.vieworg, NECK_LENGTH, up, cg.refdef.vieworg ); } #endif }
/* =============== CG_OffsetFirstPersonView =============== */ static void CG_OffsetFirstPersonView( void ) { float* origin; float* angles; float delta; float speed; float f; vec3_c predictedVelocity; int timeDelta; origin = cg.refdefViewOrigin; angles = cg.refdefViewAngles; // add angles based on velocity predictedVelocity = cg.predictedPlayerState.velocity;; //delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[0]); //angles[PITCH] += delta * cg_runpitch.value; // //delta = DotProduct ( predictedVelocity, cg.refdef.viewaxis[1]); //angles[ROLL] -= delta * cg_runroll.value; // add angles based on bob // make sure the bob is visible even at low speeds speed = 200; //=================================== // add view height origin[2] += cg.predictedPlayerState.viewheight; // smooth out duck height changes timeDelta = cg.time - cg.duckTime; if ( timeDelta < DUCK_TIME ) { cg.refdefViewOrigin[2] -= cg.duckChange * ( DUCK_TIME - timeDelta ) / DUCK_TIME; } // add fall height delta = cg.time - cg.landTime; if ( delta < LAND_DEFLECT_TIME ) { f = delta / LAND_DEFLECT_TIME; cg.refdefViewOrigin[2] += cg.landChange * f; } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) { delta -= LAND_DEFLECT_TIME; f = 1.0 - ( delta / LAND_RETURN_TIME ); cg.refdefViewOrigin[2] += cg.landChange * f; } // add step offset CG_StepOffset(); }
static void CG_OffsetFirstPersonView(void) { float *origin; float *angles; float delta; float f; int timeDelta; if (cg.snap->ps.pm_type == PM_INTERMISSION) { return; } origin = cg.refdef.vieworg; angles = cg.refdefViewAngles; // if dead, fix the angle and don't add any kick if (cg.snap->ps.stats[STAT_HEALTH] <= 0) { angles[ROLL] = 40; angles[PITCH] = -15; angles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW]; origin[2] += cg.predictedPlayerState.viewheight; return; } // add view height origin[2] += cg.predictedPlayerState.viewheight; // smooth out duck height changes timeDelta = cg.time - cg.duckTime; if (timeDelta < DUCK_TIME) { cg.refdef.vieworg[2] -= cg.duckChange * (DUCK_TIME - timeDelta) / DUCK_TIME; } // add fall height delta = cg.time - cg.landTime; if (delta < LAND_DEFLECT_TIME) { f = delta / LAND_DEFLECT_TIME; cg.refdef.vieworg[2] += cg.landChange * f; } else if (delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME) { delta -= LAND_DEFLECT_TIME; f = 1.0 - (delta / LAND_RETURN_TIME); cg.refdef.vieworg[2] += cg.landChange * f; } // add step offset CG_StepOffset(); // pivot the eye based on a neck length #if 0 { #define NECK_LENGTH 8 vec3_t forward, up; cg.refdef.vieworg[2] -= NECK_LENGTH; AngleVectors(cg.refdefViewAngles, forward, NULL, up); VectorMA(cg.refdef.vieworg, 3, forward, cg.refdef.vieworg); VectorMA(cg.refdef.vieworg, NECK_LENGTH, up, cg.refdef.vieworg); } #endif }