Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

bg_slidemove.c (8815B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 //
     23 // bg_slidemove.c -- part of bg_pmove functionality
     24 
     25 #include "q_shared.h"
     26 #include "bg_public.h"
     27 #include "bg_local.h"
     28 
     29 /*
     30 
     31 input: origin, velocity, bounds, groundPlane, trace function
     32 
     33 output: origin, velocity, impacts, stairup boolean
     34 
     35 */
     36 
     37 /*
     38 ==================
     39 PM_SlideMove
     40 
     41 Returns qtrue if the velocity was clipped in some way
     42 ==================
     43 */
     44 #define	MAX_CLIP_PLANES	5
     45 qboolean	PM_SlideMove( qboolean gravity ) {
     46 	int			bumpcount, numbumps;
     47 	vec3_t		dir;
     48 	float		d;
     49 	int			numplanes;
     50 	vec3_t		planes[MAX_CLIP_PLANES];
     51 	vec3_t		primal_velocity;
     52 	vec3_t		clipVelocity;
     53 	int			i, j, k;
     54 	trace_t	trace;
     55 	vec3_t		end;
     56 	float		time_left;
     57 	float		into;
     58 	vec3_t		endVelocity;
     59 	vec3_t		endClipVelocity;
     60 	
     61 	numbumps = 4;
     62 
     63 	VectorCopy (pm->ps->velocity, primal_velocity);
     64 
     65 	if ( gravity ) {
     66 		VectorCopy( pm->ps->velocity, endVelocity );
     67 		endVelocity[2] -= pm->ps->gravity * pml.frametime;
     68 		pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5;
     69 		primal_velocity[2] = endVelocity[2];
     70 		if ( pml.groundPlane ) {
     71 			// slide along the ground plane
     72 			PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, 
     73 				pm->ps->velocity, OVERCLIP );
     74 		}
     75 	}
     76 
     77 	time_left = pml.frametime;
     78 
     79 	// never turn against the ground plane
     80 	if ( pml.groundPlane ) {
     81 		numplanes = 1;
     82 		VectorCopy( pml.groundTrace.plane.normal, planes[0] );
     83 	} else {
     84 		numplanes = 0;
     85 	}
     86 
     87 	// never turn against original velocity
     88 	VectorNormalize2( pm->ps->velocity, planes[numplanes] );
     89 	numplanes++;
     90 
     91 	for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {
     92 
     93 		// calculate position we are trying to move to
     94 		VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );
     95 
     96 		// see if we can make it there
     97 		pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask);
     98 
     99 		if (trace.allsolid) {
    100 			// entity is completely trapped in another solid
    101 			pm->ps->velocity[2] = 0;	// don't build up falling damage, but allow sideways acceleration
    102 			return qtrue;
    103 		}
    104 
    105 		if (trace.fraction > 0) {
    106 			// actually covered some distance
    107 			VectorCopy (trace.endpos, pm->ps->origin);
    108 		}
    109 
    110 		if (trace.fraction == 1) {
    111 			 break;		// moved the entire distance
    112 		}
    113 
    114 		// save entity for contact
    115 		PM_AddTouchEnt( trace.entityNum );
    116 
    117 		time_left -= time_left * trace.fraction;
    118 
    119 		if (numplanes >= MAX_CLIP_PLANES) {
    120 			// this shouldn't really happen
    121 			VectorClear( pm->ps->velocity );
    122 			return qtrue;
    123 		}
    124 
    125 		//
    126 		// if this is the same plane we hit before, nudge velocity
    127 		// out along it, which fixes some epsilon issues with
    128 		// non-axial planes
    129 		//
    130 		for ( i = 0 ; i < numplanes ; i++ ) {
    131 			if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) {
    132 				VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity );
    133 				break;
    134 			}
    135 		}
    136 		if ( i < numplanes ) {
    137 			continue;
    138 		}
    139 		VectorCopy (trace.plane.normal, planes[numplanes]);
    140 		numplanes++;
    141 
    142 		//
    143 		// modify velocity so it parallels all of the clip planes
    144 		//
    145 
    146 		// find a plane that it enters
    147 		for ( i = 0 ; i < numplanes ; i++ ) {
    148 			into = DotProduct( pm->ps->velocity, planes[i] );
    149 			if ( into >= 0.1 ) {
    150 				continue;		// move doesn't interact with the plane
    151 			}
    152 
    153 			// see how hard we are hitting things
    154 			if ( -into > pml.impactSpeed ) {
    155 				pml.impactSpeed = -into;
    156 			}
    157 
    158 			// slide along the plane
    159 			PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );
    160 
    161 			// slide along the plane
    162 			PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP );
    163 
    164 			// see if there is a second plane that the new move enters
    165 			for ( j = 0 ; j < numplanes ; j++ ) {
    166 				if ( j == i ) {
    167 					continue;
    168 				}
    169 				if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {
    170 					continue;		// move doesn't interact with the plane
    171 				}
    172 
    173 				// try clipping the move to the plane
    174 				PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP );
    175 				PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP );
    176 
    177 				// see if it goes back into the first clip plane
    178 				if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) {
    179 					continue;
    180 				}
    181 
    182 				// slide the original velocity along the crease
    183 				CrossProduct (planes[i], planes[j], dir);
    184 				VectorNormalize( dir );
    185 				d = DotProduct( dir, pm->ps->velocity );
    186 				VectorScale( dir, d, clipVelocity );
    187 
    188 				CrossProduct (planes[i], planes[j], dir);
    189 				VectorNormalize( dir );
    190 				d = DotProduct( dir, endVelocity );
    191 				VectorScale( dir, d, endClipVelocity );
    192 
    193 				// see if there is a third plane the the new move enters
    194 				for ( k = 0 ; k < numplanes ; k++ ) {
    195 					if ( k == i || k == j ) {
    196 						continue;
    197 					}
    198 					if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {
    199 						continue;		// move doesn't interact with the plane
    200 					}
    201 
    202 					// stop dead at a tripple plane interaction
    203 					VectorClear( pm->ps->velocity );
    204 					return qtrue;
    205 				}
    206 			}
    207 
    208 			// if we have fixed all interactions, try another move
    209 			VectorCopy( clipVelocity, pm->ps->velocity );
    210 			VectorCopy( endClipVelocity, endVelocity );
    211 			break;
    212 		}
    213 	}
    214 
    215 	if ( gravity ) {
    216 		VectorCopy( endVelocity, pm->ps->velocity );
    217 	}
    218 
    219 	// don't change velocity if in a timer (FIXME: is this correct?)
    220 	if ( pm->ps->pm_time ) {
    221 		VectorCopy( primal_velocity, pm->ps->velocity );
    222 	}
    223 
    224 	return ( bumpcount != 0 );
    225 }
    226 
    227 /*
    228 ==================
    229 PM_StepSlideMove
    230 
    231 ==================
    232 */
    233 void PM_StepSlideMove( qboolean gravity ) {
    234 	vec3_t		start_o, start_v;
    235 	vec3_t		down_o, down_v;
    236 	trace_t		trace;
    237 //	float		down_dist, up_dist;
    238 //	vec3_t		delta, delta2;
    239 	vec3_t		up, down;
    240 	float		stepSize;
    241 
    242 	VectorCopy (pm->ps->origin, start_o);
    243 	VectorCopy (pm->ps->velocity, start_v);
    244 
    245 	if ( PM_SlideMove( gravity ) == 0 ) {
    246 		return;		// we got exactly where we wanted to go first try	
    247 	}
    248 
    249 	VectorCopy(start_o, down);
    250 	down[2] -= STEPSIZE;
    251 	pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
    252 	VectorSet(up, 0, 0, 1);
    253 	// never step up when you still have up velocity
    254 	if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 ||
    255 										DotProduct(trace.plane.normal, up) < 0.7)) {
    256 		return;
    257 	}
    258 
    259 	VectorCopy (pm->ps->origin, down_o);
    260 	VectorCopy (pm->ps->velocity, down_v);
    261 
    262 	VectorCopy (start_o, up);
    263 	up[2] += STEPSIZE;
    264 
    265 	// test the player position if they were a stepheight higher
    266 	pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask);
    267 	if ( trace.allsolid ) {
    268 		if ( pm->debugLevel ) {
    269 			Com_Printf("%i:bend can't step\n", c_pmove);
    270 		}
    271 		return;		// can't step up
    272 	}
    273 
    274 	stepSize = trace.endpos[2] - start_o[2];
    275 	// try slidemove from this position
    276 	VectorCopy (trace.endpos, pm->ps->origin);
    277 	VectorCopy (start_v, pm->ps->velocity);
    278 
    279 	PM_SlideMove( gravity );
    280 
    281 	// push down the final amount
    282 	VectorCopy (pm->ps->origin, down);
    283 	down[2] -= stepSize;
    284 	pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
    285 	if ( !trace.allsolid ) {
    286 		VectorCopy (trace.endpos, pm->ps->origin);
    287 	}
    288 	if ( trace.fraction < 1.0 ) {
    289 		PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
    290 	}
    291 
    292 #if 0
    293 	// if the down trace can trace back to the original position directly, don't step
    294 	pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, start_o, pm->ps->clientNum, pm->tracemask);
    295 	if ( trace.fraction == 1.0 ) {
    296 		// use the original move
    297 		VectorCopy (down_o, pm->ps->origin);
    298 		VectorCopy (down_v, pm->ps->velocity);
    299 		if ( pm->debugLevel ) {
    300 			Com_Printf("%i:bend\n", c_pmove);
    301 		}
    302 	} else 
    303 #endif
    304 	{
    305 		// use the step move
    306 		float	delta;
    307 
    308 		delta = pm->ps->origin[2] - start_o[2];
    309 		if ( delta > 2 ) {
    310 			if ( delta < 7 ) {
    311 				PM_AddEvent( EV_STEP_4 );
    312 			} else if ( delta < 11 ) {
    313 				PM_AddEvent( EV_STEP_8 );
    314 			} else if ( delta < 15 ) {
    315 				PM_AddEvent( EV_STEP_12 );
    316 			} else {
    317 				PM_AddEvent( EV_STEP_16 );
    318 			}
    319 		}
    320 		if ( pm->debugLevel ) {
    321 			Com_Printf("%i:stepped\n", c_pmove);
    322 		}
    323 	}
    324 }
    325