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