summaryrefslogtreecommitdiff
path: root/src/game/bg_slidemove.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/bg_slidemove.c')
-rw-r--r--src/game/bg_slidemove.c416
1 files changed, 416 insertions, 0 deletions
diff --git a/src/game/bg_slidemove.c b/src/game/bg_slidemove.c
new file mode 100644
index 0000000..1f62bfa
--- /dev/null
+++ b/src/game/bg_slidemove.c
@@ -0,0 +1,416 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2006 Tim Angus
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+// bg_slidemove.c -- part of bg_pmove functionality
+
+#include "../qcommon/q_shared.h"
+#include "bg_public.h"
+#include "bg_local.h"
+
+/*
+
+input: origin, velocity, bounds, groundPlane, trace function
+
+output: origin, velocity, impacts, stairup boolean
+
+*/
+
+/*
+==================
+PM_SlideMove
+
+Returns qtrue if the velocity was clipped in some way
+==================
+*/
+#define MAX_CLIP_PLANES 5
+qboolean PM_SlideMove( qboolean gravity )
+{
+ int bumpcount, numbumps;
+ vec3_t dir;
+ float d;
+ int numplanes;
+ vec3_t planes[MAX_CLIP_PLANES];
+ vec3_t primal_velocity;
+ vec3_t clipVelocity;
+ int i, j, k;
+ trace_t trace;
+ vec3_t end;
+ float time_left;
+ float into;
+ vec3_t endVelocity;
+ vec3_t endClipVelocity;
+
+ numbumps = 4;
+
+ VectorCopy( pm->ps->velocity, primal_velocity );
+
+ if( gravity )
+ {
+ VectorCopy( pm->ps->velocity, endVelocity );
+ endVelocity[ 2 ] -= pm->ps->gravity * pml.frametime;
+ pm->ps->velocity[ 2 ] = ( pm->ps->velocity[ 2 ] + endVelocity[ 2 ] ) * 0.5;
+ primal_velocity[ 2 ] = endVelocity[ 2 ];
+
+ if( pml.groundPlane )
+ {
+ // slide along the ground plane
+ PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal,
+ pm->ps->velocity, OVERCLIP );
+ }
+ }
+
+ time_left = pml.frametime;
+
+ // never turn against the ground plane
+ if( pml.groundPlane )
+ {
+ numplanes = 1;
+ VectorCopy( pml.groundTrace.plane.normal, planes[ 0 ] );
+ }
+ else
+ numplanes = 0;
+
+ // never turn against original velocity
+ VectorNormalize2( pm->ps->velocity, planes[ numplanes ] );
+ numplanes++;
+
+ for( bumpcount = 0; bumpcount < numbumps; bumpcount++ )
+ {
+ // calculate position we are trying to move to
+ VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );
+
+ // see if we can make it there
+ pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask );
+
+ if( trace.allsolid )
+ {
+ // entity is completely trapped in another solid
+ pm->ps->velocity[ 2 ] = 0; // don't build up falling damage, but allow sideways acceleration
+ return qtrue;
+ }
+
+ if( trace.fraction > 0 )
+ {
+ // actually covered some distance
+ VectorCopy( trace.endpos, pm->ps->origin );
+ }
+
+ if( trace.fraction == 1 )
+ break; // moved the entire distance
+
+ // save entity for contact
+ PM_AddTouchEnt( trace.entityNum );
+
+ time_left -= time_left * trace.fraction;
+
+ if( numplanes >= MAX_CLIP_PLANES )
+ {
+ // this shouldn't really happen
+ VectorClear( pm->ps->velocity );
+ return qtrue;
+ }
+
+ //
+ // if this is the same plane we hit before, nudge velocity
+ // out along it, which fixes some epsilon issues with
+ // non-axial planes
+ //
+ for( i = 0 ; i < numplanes ; i++ )
+ {
+ if( DotProduct( trace.plane.normal, planes[i] ) > 0.99 )
+ {
+ VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity );
+ break;
+ }
+ }
+
+ if( i < numplanes )
+ continue;
+
+ VectorCopy( trace.plane.normal, planes[ numplanes ] );
+ numplanes++;
+
+ //
+ // modify velocity so it parallels all of the clip planes
+ //
+
+ // find a plane that it enters
+ for( i = 0; i < numplanes; i++ )
+ {
+ into = DotProduct( pm->ps->velocity, planes[ i ] );
+ if( into >= 0.1 )
+ continue; // move doesn't interact with the plane
+
+ // see how hard we are hitting things
+ if( -into > pml.impactSpeed )
+ pml.impactSpeed = -into;
+
+ // slide along the plane
+ PM_ClipVelocity( pm->ps->velocity, planes[ i ], clipVelocity, OVERCLIP );
+
+ // slide along the plane
+ PM_ClipVelocity( endVelocity, planes[ i ], endClipVelocity, OVERCLIP );
+
+ // see if there is a second plane that the new move enters
+ for( j = 0; j < numplanes; j++ )
+ {
+ if( j == i )
+ continue;
+
+ if( DotProduct( clipVelocity, planes[ j ] ) >= 0.1 )
+ continue; // move doesn't interact with the plane
+
+ // try clipping the move to the plane
+ PM_ClipVelocity( clipVelocity, planes[ j ], clipVelocity, OVERCLIP );
+ PM_ClipVelocity( endClipVelocity, planes[ j ], endClipVelocity, OVERCLIP );
+
+ // see if it goes back into the first clip plane
+ if( DotProduct( clipVelocity, planes[ i ] ) >= 0 )
+ continue;
+
+ // slide the original velocity along the crease
+ CrossProduct( planes[ i ], planes[ j ], dir );
+ VectorNormalize( dir );
+ d = DotProduct( dir, pm->ps->velocity );
+ VectorScale( dir, d, clipVelocity );
+
+ CrossProduct( planes[ i ], planes[ j ], dir);
+ VectorNormalize( dir );
+ d = DotProduct( dir, endVelocity );
+ VectorScale( dir, d, endClipVelocity );
+
+ // see if there is a third plane the the new move enters
+ for( k = 0; k < numplanes; k++ )
+ {
+ if( k == i || k == j )
+ continue;
+
+ if( DotProduct( clipVelocity, planes[ k ] ) >= 0.1 )
+ continue; // move doesn't interact with the plane
+
+ // stop dead at a tripple plane interaction
+ VectorClear( pm->ps->velocity );
+ return qtrue;
+ }
+ }
+
+ // if we have fixed all interactions, try another move
+ VectorCopy( clipVelocity, pm->ps->velocity );
+ VectorCopy( endClipVelocity, endVelocity );
+ break;
+ }
+ }
+
+ if( gravity )
+ VectorCopy( endVelocity, pm->ps->velocity );
+
+ // don't change velocity if in a timer (FIXME: is this correct?)
+ if( pm->ps->pm_time )
+ VectorCopy( primal_velocity, pm->ps->velocity );
+
+ return ( bumpcount != 0 );
+}
+
+/*
+==================
+PM_StepEvent
+==================
+*/
+void PM_StepEvent( vec3_t from, vec3_t to, vec3_t normal )
+{
+ float size;
+ vec3_t delta, dNormal;
+
+ VectorSubtract( from, to, delta );
+ VectorCopy( delta, dNormal );
+ VectorNormalize( dNormal );
+
+ size = DotProduct( normal, dNormal ) * VectorLength( delta );
+
+ if( size > 0.0f )
+ {
+ if( size > 2.0f )
+ {
+ if( size < 7.0f )
+ PM_AddEvent( EV_STEPDN_4 );
+ else if( size < 11.0f )
+ PM_AddEvent( EV_STEPDN_8 );
+ else if( size < 15.0f )
+ PM_AddEvent( EV_STEPDN_12 );
+ else
+ PM_AddEvent( EV_STEPDN_16 );
+ }
+ }
+ else
+ {
+ size = fabs( size );
+
+ if( size > 2.0f )
+ {
+ if( size < 7.0f )
+ PM_AddEvent( EV_STEP_4 );
+ else if( size < 11.0f )
+ PM_AddEvent( EV_STEP_8 );
+ else if( size < 15.0f )
+ PM_AddEvent( EV_STEP_12 );
+ else
+ PM_AddEvent( EV_STEP_16 );
+ }
+ }
+
+ if( pm->debugLevel )
+ Com_Printf( "%i:stepped\n", c_pmove );
+}
+
+/*
+==================
+PM_StepSlideMove
+==================
+*/
+qboolean PM_StepSlideMove( qboolean gravity, qboolean predictive )
+{
+ vec3_t start_o, start_v;
+ vec3_t down_o, down_v;
+ trace_t trace;
+ vec3_t normal;
+ vec3_t step_v, step_vNormal;
+ vec3_t up, down;
+ float stepSize;
+ qboolean stepped = qfalse;
+
+ if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
+ {
+ if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
+ VectorSet( normal, 0.0f, 0.0f, -1.0f );
+ else
+ VectorCopy( pm->ps->grapplePoint, normal );
+ }
+ else
+ VectorSet( normal, 0.0f, 0.0f, 1.0f );
+
+ VectorCopy( pm->ps->origin, start_o );
+ VectorCopy( pm->ps->velocity, start_v );
+
+ if( PM_SlideMove( gravity ) == 0 )
+ {
+ VectorCopy( start_o, down );
+ VectorMA( down, -STEPSIZE, normal, down );
+ pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );
+
+ //we can step down
+ if( trace.fraction > 0.01f && trace.fraction < 1.0f &&
+ !trace.allsolid && pml.groundPlane != qfalse )
+ {
+ if( pm->debugLevel )
+ Com_Printf( "%d: step down\n", c_pmove );
+
+ stepped = qtrue;
+ }
+ }
+ else
+ {
+ VectorCopy( start_o, down );
+ VectorMA( down, -STEPSIZE, normal, down );
+ pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );
+ // never step up when you still have up velocity
+ if( DotProduct( trace.plane.normal, pm->ps->velocity ) > 0.0f &&
+ ( trace.fraction == 1.0f || DotProduct( trace.plane.normal, normal ) < 0.7f ) )
+ {
+ return stepped;
+ }
+
+ VectorCopy( pm->ps->origin, down_o );
+ VectorCopy( pm->ps->velocity, down_v );
+
+ VectorCopy( start_o, up );
+ VectorMA( up, STEPSIZE, normal, up );
+
+ // test the player position if they were a stepheight higher
+ pm->trace( &trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask );
+ if( trace.allsolid )
+ {
+ if( pm->debugLevel )
+ Com_Printf( "%i:bend can't step\n", c_pmove );
+
+ return stepped; // can't step up
+ }
+
+ VectorSubtract( trace.endpos, start_o, step_v );
+ VectorCopy( step_v, step_vNormal );
+ VectorNormalize( step_vNormal );
+
+ stepSize = DotProduct( normal, step_vNormal ) * VectorLength( step_v );
+ // try slidemove from this position
+ VectorCopy( trace.endpos, pm->ps->origin );
+ VectorCopy( start_v, pm->ps->velocity );
+
+ if( PM_SlideMove( gravity ) == 0 )
+ {
+ if( pm->debugLevel )
+ Com_Printf( "%d: step up\n", c_pmove );
+
+ stepped = qtrue;
+ }
+
+ // push down the final amount
+ VectorCopy( pm->ps->origin, down );
+ VectorMA( down, -stepSize, normal, down );
+ pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );
+
+ if( !trace.allsolid )
+ VectorCopy( trace.endpos, pm->ps->origin );
+
+ if( trace.fraction < 1.0f )
+ PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
+ }
+
+ if( !predictive && stepped )
+ PM_StepEvent( start_o, pm->ps->origin, normal );
+
+ return stepped;
+}
+
+/*
+==================
+PM_PredictStepMove
+==================
+*/
+qboolean PM_PredictStepMove( void )
+{
+ vec3_t velocity, origin;
+ float impactSpeed;
+ qboolean stepped = qfalse;
+
+ VectorCopy( pm->ps->velocity, velocity );
+ VectorCopy( pm->ps->origin, origin );
+ impactSpeed = pml.impactSpeed;
+
+ if( PM_StepSlideMove( qfalse, qtrue ) )
+ stepped = qtrue;
+
+ VectorCopy( velocity, pm->ps->velocity );
+ VectorCopy( origin, pm->ps->origin );
+ pml.impactSpeed = impactSpeed;
+
+ return stepped;
+}