diff options
Diffstat (limited to 'src/cgame')
-rw-r--r-- | src/cgame/cg_draw.c | 8 | ||||
-rw-r--r-- | src/cgame/cg_local.h | 7 | ||||
-rw-r--r-- | src/cgame/cg_main.c | 2 | ||||
-rw-r--r-- | src/cgame/cg_tutorial.c | 4 | ||||
-rw-r--r-- | src/cgame/cg_view.c | 239 |
5 files changed, 202 insertions, 58 deletions
diff --git a/src/cgame/cg_draw.c b/src/cgame/cg_draw.c index a2e5fc91..13412eef 100644 --- a/src/cgame/cg_draw.c +++ b/src/cgame/cg_draw.c @@ -2931,7 +2931,8 @@ static void CG_DrawIntermission( void ) cg.scoreBoardShowing = CG_DrawScoreboard( ); } -#define FOLLOWING_STRING "following " +#define FOLLOWING_STRING "Following: " +#define CHASING_STRING "Chasing: " /* ================= @@ -2952,7 +2953,10 @@ static qboolean CG_DrawFollow( void ) color[ 2 ] = 1; color[ 3 ] = 1; - strcpy( buffer, FOLLOWING_STRING ); + if( !cg.chaseFollow ) + strcpy( buffer, FOLLOWING_STRING ); + else + strcpy( buffer, CHASING_STRING ); strcat( buffer, cgs.clientinfo[ cg.snap->ps.clientNum ].name ); w = UI_Text_Width( buffer, 0.7f, 0 ); diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h index 4c384a8e..2fa1b756 100644 --- a/src/cgame/cg_local.h +++ b/src/cgame/cg_local.h @@ -1100,8 +1100,7 @@ typedef struct vec3_t kick_angles; // weapon kicks vec3_t kick_origin; - - qboolean thirdPersonFollow; + qboolean chaseFollow; // temp working variables for player view float bobfracsin; @@ -1486,6 +1485,7 @@ extern vmCvar_t cg_tracerLength; extern vmCvar_t cg_autoswitch; extern vmCvar_t cg_thirdPerson; extern vmCvar_t cg_thirdPersonRange; +extern vmCvar_t cg_thirdPersonShoulderView; extern vmCvar_t cg_stereoSeparation; extern vmCvar_t cg_lagometer; extern vmCvar_t cg_synchronousClients; @@ -1593,6 +1593,9 @@ void CG_TestModelNextSkin_f( void ); void CG_TestModelPrevSkin_f( void ); void CG_AddBufferedSound( sfxHandle_t sfx ); void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ); +void CG_OffsetFirstPersonView( void ); +void CG_OffsetThirdPersonView( void ); +void CG_OffsetShoulderView( void ); // diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c index d70e151b..8aa3b52c 100644 --- a/src/cgame/cg_main.c +++ b/src/cgame/cg_main.c @@ -142,6 +142,7 @@ vmCvar_t cg_tracerWidth; vmCvar_t cg_tracerLength; vmCvar_t cg_autoswitch; vmCvar_t cg_thirdPerson; +vmCvar_t cg_thirdPersonShoulderView; vmCvar_t cg_thirdPersonRange; vmCvar_t cg_stereoSeparation; vmCvar_t cg_lagometer; @@ -264,6 +265,7 @@ static cvarTable_t cvarTable[ ] = { &cg_tracerWidth, "cg_tracerwidth", "1", CVAR_CHEAT }, { &cg_tracerLength, "cg_tracerlength", "100", CVAR_CHEAT }, { &cg_thirdPersonRange, "cg_thirdPersonRange", "75", CVAR_ARCHIVE }, + { &cg_thirdPersonShoulderView, "cg_thirdPersonShoulderView", "0", CVAR_ARCHIVE }, { &cg_thirdPerson, "cg_thirdPerson", "0", CVAR_CHEAT }, { &cg_stats, "cg_stats", "0", 0 }, { &cg_drawFriend, "cg_drawFriend", "1", CVAR_ARCHIVE }, diff --git a/src/cgame/cg_tutorial.c b/src/cgame/cg_tutorial.c index 77d0d8fb..01d82e5c 100644 --- a/src/cgame/cg_tutorial.c +++ b/src/cgame/cg_tutorial.c @@ -574,9 +574,9 @@ static void CG_SpectatorText( char *text, playerState_t *ps ) if( ps->pm_flags & PMF_FOLLOW ) { - if( !cg.thirdPersonFollow ) + if( !cg.chaseFollow ) Q_strcat( text, MAX_TUTORIAL_TEXT, - va( "Press %s to switch to third-person spectator mode\n", + va( "Press %s to switch to chase-cam spectator mode\n", CG_KeyNameForCommand( "+button2" ) ) ); else Q_strcat( text, MAX_TUTORIAL_TEXT, diff --git a/src/cgame/cg_view.c b/src/cgame/cg_view.c index f49fc3af..0c13ee2d 100644 --- a/src/cgame/cg_view.c +++ b/src/cgame/cg_view.c @@ -257,105 +257,140 @@ static void CG_CalcVrect( void ) //============================================================================== - /* =============== CG_OffsetThirdPersonView =============== */ -static void CG_OffsetThirdPersonView( void ) +void CG_OffsetThirdPersonView( void ) { + int i; vec3_t forward, right, up; vec3_t view; trace_t trace; static vec3_t mins = { -8, -8, -8 }; static vec3_t maxs = { 8, 8, 8 }; vec3_t focusPoint; - float forwardScale, sideScale, upScale; vec3_t surfNormal; int cmdNum; - usercmd_t cmd, oldcmd; - float range, yaw, deltaPitch; + usercmd_t cmd, oldCmd; + float range; + vec3_t mouseInputAngles; + vec3_t rotationAngles; + vec3_t axis[ 3 ], rotaxis[ 3 ]; + float deltaPitch; static float pitch; - // set the view origin to the class's view height + + + // If cg_thirdpersonShoulderView, run that function instead + // If we're chasing a wallwalker, do shoulder view regardless + // because actual third person creates lots of problems otherwise. + if( ( cg_thirdPersonShoulderView.integer ) || + ( ( cg.snap->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING ) && + ( cg.snap->ps.stats[ STAT_HEALTH ] > 0 ) ) ) + { + CG_OffsetShoulderView( ); + return; + } + BG_GetClientNormal( &cg.predictedPlayerState, surfNormal ); + // set the view origin to the class's view height VectorMA( cg.refdef.vieworg, cg.predictedPlayerState.viewheight, surfNormal, cg.refdef.vieworg ); // set the focus point where the camera will look (at the player's vieworg) VectorCopy( cg.refdef.vieworg, focusPoint ); - // collect our input values from cvars and the mouse - cmdNum = trap_GetCurrentCmdNumber(); - trap_GetUserCmd( cmdNum, &cmd ); - trap_GetUserCmd( cmdNum - 1, &oldcmd ); + // if player is dead, we want the player to be between us and the killer + // so pretend that the player was looking at the killer, then place cam behind them + // FIXME: Still fails to see killer when killer is above/below or killer moves + // out of view (relative to the dead player) + if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 ) + cg.refdefViewAngles[ YAW ] = cg.predictedPlayerState.stats[ STAT_VIEWLOCK ]; - // unless in demo, PLAYING in third person, or in dead-third-person cam, control camera position - // offsets using the mouse position + // Calculate the angle of the camera's position around the player + // unless in demo, PLAYING in third person, or in dead-third-person cam, allow the player + // to control camera position offsets using the mouse position if( cg.demoPlayback || ( ( cg.snap->ps.pm_flags & PMF_FOLLOW ) && ( cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 ) ) ) { - // Get our yaw offset - yaw = -1.0f * SHORT2ANGLE(cmd.angles[ YAW ]); + // collect our input values from the mouse + cmdNum = trap_GetCurrentCmdNumber(); + trap_GetUserCmd( cmdNum, &cmd ); + trap_GetUserCmd( cmdNum - 1, &oldCmd ); - // Get our pitch offset - // Don't let it exceed 90 or -90 and prevent wrapping by cmd.angles from mucking this up. - deltaPitch = SHORT2ANGLE( cmd.angles[ PITCH ] ) - SHORT2ANGLE ( oldcmd.angles[ PITCH ] ); + + // prevent pitch from wrapping and clamp it within a [-75, 90] range + // cgame has no access to ps.delta_angles[] here, so we need to reproduce + // it ourselves + deltaPitch = SHORT2ANGLE( cmd.angles[ PITCH ] - oldCmd.angles[ PITCH ] ); if( fabs(deltaPitch) < 200.0f ) { - if( pitch + deltaPitch > 110.0f ) pitch = 110.0f; - else if( pitch + deltaPitch < 1.0f ) pitch = 1.0f; - else pitch += deltaPitch; + if( pitch + deltaPitch > 90.0f ) pitch = 90.0f; + else if( pitch + deltaPitch < -75.0f ) pitch = -75.0f; + else pitch += deltaPitch; + } + + mouseInputAngles[ PITCH ] = pitch; + mouseInputAngles[ YAW ] = -1.0f * SHORT2ANGLE( cmd.angles[ YAW ] ); //yaw is inverted + mouseInputAngles[ ROLL ] = 0.0f; + + // Set the rotation angles to be the view angles offset by the mouse input + for( i = 0; i < 3; i++ ) + { + rotationAngles[ i ] = cg.refdefViewAngles[ i ] + mouseInputAngles[ i ]; + AngleNormalize180( rotationAngles[ i ] ); } } else { - yaw = 90.0f; - pitch = 85.0f; + // If we're playing the game in third person, the viewangles already + // take care of our mouselook, so just use them + for( i = 0; i < 3; i++ ) + rotationAngles[ i ] = cg.refdefViewAngles[ i ]; } + // get and rangecheck cg_thirdPersonRange range = cg_thirdPersonRange.value; if( range > 150.0f ) range = 150.0f; if( range < 30.0f ) range = 30.0f; - // calculate the camera position by moving to the appropriate position on a - // sphere around the player relative to where he is looking, and with radius 'range' - // if player is dead, we want the player to be between us and the killer - // so pretend that the player was looking at the killer, then place cam behind them - // FIXME: Still fails to see killer when killer is above/below or killer moves - // out of view (relative to the dead player) - if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 ) - cg.refdefViewAngles[ YAW ] = cg.predictedPlayerState.stats[ STAT_VIEWLOCK ]; + // calculate the camera position relative to the player's viewaxis + + // perform the rotations specified by rotationAngles + AnglesToAxis( rotationAngles, axis ); + if( !( cg.snap->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING ) || + !BG_RotateAxis( cg.snap->ps.grapplePoint, axis, rotaxis, qfalse, + cg.snap->ps.eFlags & EF_WALLCLIMBCEILING ) ) + AxisCopy( axis, rotaxis ); - // if we're following a live player, don't move with their pitch - // because it's really jerky to watch and causes problems when our - // angle relative to theirs causes angles to wrap and views flip out - if( cg.snap->ps.pm_flags & PMF_FOLLOW ) - cg.refdefViewAngles[ PITCH ] = 0.0f; + // convert the new axis back to angles + AxisToAngles( rotaxis, rotationAngles ); - AngleVectors( cg.refdefViewAngles, forward, right, up ); - sideScale = sin( DEG2RAD( pitch ) ) * cos( DEG2RAD( yaw ) ); - forwardScale = sin( DEG2RAD( pitch ) ) * sin( DEG2RAD( yaw ) ); - upScale = cos( DEG2RAD( pitch ) ); + // force angles to -180 <= x <= 180 + for( i = 0; i < 3; i++ ) + AngleNormalize180( rotationAngles[ i ] ); + // move the camera range distance back + AngleVectors( rotationAngles, forward, right, up ); VectorCopy( cg.refdef.vieworg, view ); - VectorMA( view, -range * forwardScale, forward, view ); - VectorMA( view, range * sideScale, right, view ); - VectorMA( view, range * upScale, up, view ); + VectorMA( view, -range, forward, view ); - // trace a ray from the origin to the viewpoint to make sure the view isn't - // in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything + // ensure that the current camera position isn't out of bounds and that there + // is nothing between the camera and the player if( !cg_cameraMode.integer ) { + // trace a ray from the origin to the viewpoint to make sure the view isn't + // in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID ); - if( trace.fraction != 1.0 ) + if( trace.fraction != 1.0f ) { VectorCopy( trace.endpos, view ); - view[ 2 ] += ( 1.0 - trace.fraction ) * 32; + view[ 2 ] += ( 1.0f - trace.fraction ) * 32; // try another trace to this position, because a tunnel may have the ceiling // close enogh that this is poking out @@ -367,11 +402,111 @@ static void CG_OffsetThirdPersonView( void ) // set the camera position to what we calculated VectorCopy( view, cg.refdef.vieworg ); - // from the camera position, look at the target + // the above checks may have moved the camera such that the existing viewangles + // may not still face the player. Recalculate them to do so. VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint ); vectoangles( focusPoint, cg.refdefViewAngles ); } + +/* +=============== +CG_OffsetShoulderView + +=============== +*/ +void CG_OffsetShoulderView( void ) +{ + int i; + vec3_t surfNormal; + int cmdNum; + usercmd_t cmd, oldCmd; + vec3_t rotationAngles; + vec3_t axis[ 3 ], rotaxis[ 3 ]; + float deltaPitch; + static float pitch; + + + BG_GetClientNormal( &cg.predictedPlayerState, surfNormal ); + + // boost the camera up a little bit from the vieworigin so you aren't inside + switch( cg.snap->ps.stats[ STAT_CLASS ] ) + { + case PCL_ALIEN_LEVEL0: + VectorMA( cg.refdef.vieworg, 15.0f, surfNormal, cg.refdef.vieworg ); + break; + case PCL_ALIEN_LEVEL1: + case PCL_ALIEN_LEVEL1_UPG: + VectorMA( cg.refdef.vieworg, 20.0f, surfNormal, cg.refdef.vieworg ); + break; + case PCL_ALIEN_LEVEL2: + case PCL_ALIEN_LEVEL2_UPG: + VectorMA( cg.refdef.vieworg, 10.0f, surfNormal, cg.refdef.vieworg ); + break; + case PCL_ALIEN_LEVEL3: + VectorMA( cg.refdef.vieworg, 8.0f, surfNormal, cg.refdef.vieworg ); + break; + case PCL_ALIEN_LEVEL3_UPG: + VectorMA( cg.refdef.vieworg, 15.0f, surfNormal, cg.refdef.vieworg ); + break; + case PCL_ALIEN_LEVEL4: + VectorMA( cg.refdef.vieworg, 35.0f, surfNormal, cg.refdef.vieworg ); + break; + case PCL_HUMAN: + VectorMA( cg.refdef.vieworg, 20.0f, surfNormal, cg.refdef.vieworg ); + break; + case PCL_HUMAN_BSUIT: + VectorMA( cg.refdef.vieworg, 26.0f, surfNormal, cg.refdef.vieworg ); + break; + } + + if( !( cg.snap->ps.pm_flags & PMF_FOLLOW ) ) + { + CG_OffsetFirstPersonView(); + return; + } + + cmdNum = trap_GetCurrentCmdNumber(); + trap_GetUserCmd( cmdNum, &cmd ); + trap_GetUserCmd( cmdNum - 1, &oldCmd ); + + // prevent pitch from wrapping and clamp it within a [30, -50] range + // cgame has no access to ps.delta_angles[] here, so we need to reproduce + // it ourselves + deltaPitch = SHORT2ANGLE( cmd.angles[ PITCH ] - oldCmd.angles[ PITCH ] ); + if( fabs(deltaPitch) < 200.0f ) + { + if( pitch + deltaPitch > 30.0f ) pitch = 30.0f; + else if( pitch + deltaPitch < -50.0f ) pitch = -50.0f; + else pitch += deltaPitch; + } + rotationAngles[ PITCH ] = pitch; + rotationAngles[ YAW ] = -1.0f * SHORT2ANGLE( cmd.angles[ YAW ] ); // yaw is inverted + rotationAngles[ ROLL ] = 0.0f; + + // convert viewangles -> axis + AnglesToAxis( rotationAngles, axis ); + + if( !( cg.snap->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING ) || + !BG_RotateAxis( cg.snap->ps.grapplePoint, axis, rotaxis, qfalse, + cg.snap->ps.eFlags & EF_WALLCLIMBCEILING ) ) + AxisCopy( axis, rotaxis ); + + // convert the new axis back to angles + AxisToAngles( rotaxis, rotationAngles ); + + // force angles to -180 <= x <= 180 + for( i = 0; i < 3; i++ ) + AngleNormalize180( rotationAngles[ i ] ); + + // actually set the viewangles + for( i = 0; i < 3; i++ ) + cg.refdefViewAngles[ i ] = rotationAngles[ i ]; + + // now run the first person stuff so we get various effects added + CG_OffsetFirstPersonView( ); +} + // this causes a compiler bug on mac MrC compiler static void CG_StepOffset( void ) { @@ -407,7 +542,7 @@ CG_OffsetFirstPersonView =============== */ -static void CG_OffsetFirstPersonView( void ) +void CG_OffsetFirstPersonView( void ) { float *origin; float *angles; @@ -726,11 +861,11 @@ static int CG_CalcFov( void ) { if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) { - if( !cg.thirdPersonFollow ) - cg.thirdPersonFollow = qtrue; + if( !cg.chaseFollow ) + cg.chaseFollow = qtrue; else { - cg.thirdPersonFollow = qfalse; + cg.chaseFollow = qfalse; trap_SendClientCommand( "follow\n" ); } } @@ -1282,7 +1417,7 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo // decide on third person view cg.renderingThirdPerson = ( cg_thirdPerson.integer || ( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 ) || - ( cg.thirdPersonFollow && cg.snap->ps.pm_flags & PMF_FOLLOW) ); + ( cg.chaseFollow && cg.snap->ps.pm_flags & PMF_FOLLOW) ); // build cg.refdef inwater = CG_CalcViewValues( ); |