2
===========================================================================
3
Copyright (C) 1999-2005 Id Software, Inc.
5
This file is part of Quake III Arena source code.
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.
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.
17
You should have received a copy of the GNU General Public License
18
along with Quake III Arena source code; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
===========================================================================
23
// bg_slidemove.c -- part of bg_pmove functionality
25
#include "../qcommon/q_shared.h"
26
#include "bg_public.h"
31
input: origin, velocity, bounds, groundPlane, trace function
33
output: origin, velocity, impacts, stairup boolean
41
Returns qtrue if the velocity was clipped in some way
44
#define MAX_CLIP_PLANES 5
45
qboolean PM_SlideMove( qboolean gravity ) {
46
int bumpcount, numbumps;
50
vec3_t planes[MAX_CLIP_PLANES];
51
vec3_t primal_velocity;
59
vec3_t endClipVelocity;
63
VectorCopy (pm->ps->velocity, primal_velocity);
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 );
77
time_left = pml.frametime;
79
// never turn against the ground plane
80
if ( pml.groundPlane ) {
82
VectorCopy( pml.groundTrace.plane.normal, planes[0] );
87
// never turn against original velocity
88
VectorNormalize2( pm->ps->velocity, planes[numplanes] );
91
for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {
93
// calculate position we are trying to move to
94
VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );
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);
100
// entity is completely trapped in another solid
101
pm->ps->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration
105
if (trace.fraction > 0) {
106
// actually covered some distance
107
VectorCopy (trace.endpos, pm->ps->origin);
110
if (trace.fraction == 1) {
111
break; // moved the entire distance
114
// save entity for contact
115
PM_AddTouchEnt( trace.entityNum );
117
time_left -= time_left * trace.fraction;
119
if (numplanes >= MAX_CLIP_PLANES) {
120
// this shouldn't really happen
121
VectorClear( pm->ps->velocity );
126
// if this is the same plane we hit before, nudge velocity
127
// out along it, which fixes some epsilon issues with
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 );
136
if ( i < numplanes ) {
139
VectorCopy (trace.plane.normal, planes[numplanes]);
143
// modify velocity so it parallels all of the clip planes
146
// find a plane that it enters
147
for ( i = 0 ; i < numplanes ; i++ ) {
148
into = DotProduct( pm->ps->velocity, planes[i] );
150
continue; // move doesn't interact with the plane
153
// see how hard we are hitting things
154
if ( -into > pml.impactSpeed ) {
155
pml.impactSpeed = -into;
158
// slide along the plane
159
PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );
161
// slide along the plane
162
PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP );
164
// see if there is a second plane that the new move enters
165
for ( j = 0 ; j < numplanes ; j++ ) {
169
if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {
170
continue; // move doesn't interact with the plane
173
// try clipping the move to the plane
174
PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP );
175
PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP );
177
// see if it goes back into the first clip plane
178
if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) {
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 );
188
CrossProduct (planes[i], planes[j], dir);
189
VectorNormalize( dir );
190
d = DotProduct( dir, endVelocity );
191
VectorScale( dir, d, endClipVelocity );
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 ) {
198
if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {
199
continue; // move doesn't interact with the plane
202
// stop dead at a tripple plane interaction
203
VectorClear( pm->ps->velocity );
208
// if we have fixed all interactions, try another move
209
VectorCopy( clipVelocity, pm->ps->velocity );
210
VectorCopy( endClipVelocity, endVelocity );
216
VectorCopy( endVelocity, pm->ps->velocity );
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 );
224
return ( bumpcount != 0 );
233
void PM_StepSlideMove( qboolean gravity ) {
234
vec3_t start_o, start_v;
235
vec3_t down_o, down_v;
237
// float down_dist, up_dist;
238
// vec3_t delta, delta2;
242
VectorCopy (pm->ps->origin, start_o);
243
VectorCopy (pm->ps->velocity, start_v);
245
if ( PM_SlideMove( gravity ) == 0 ) {
246
return; // we got exactly where we wanted to go first try
249
VectorCopy(start_o, down);
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)) {
259
VectorCopy (pm->ps->origin, down_o);
260
VectorCopy (pm->ps->velocity, down_v);
262
VectorCopy (start_o, up);
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);
271
return; // can't step up
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);
279
PM_SlideMove( gravity );
281
// push down the final amount
282
VectorCopy (pm->ps->origin, down);
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);
288
if ( trace.fraction < 1.0 ) {
289
PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
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);
308
delta = pm->ps->origin[2] - start_o[2];
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 );
317
PM_AddEvent( EV_STEP_16 );
320
if ( pm->debugLevel ) {
321
Com_Printf("%i:stepped\n", c_pmove);