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 ); VectorCopy( pm->ps->velocity, endVelocity ); if ( gravity ) { 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 ); } } 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 ); // slide along the plane PM_ClipVelocity( endVelocity, planes[ i ], endClipVelocity ); // 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 ); PM_ClipVelocity( endClipVelocity, planes[ j ], endClipVelocity ); // 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 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_GroundTrace ============= */ static void PM_GroundTrace( void ) { vec3_t point; trace_t trace; point[0] = pm->ps->origin[0]; point[1] = pm->ps->origin[1]; point[2] = pm->ps->origin[2] - 0.25; pm->trace (&trace, pm->ps->origin, pm->ps->mins, pm->ps->maxs, point, pm->ps->clientNum, pm->tracemask); pml.groundTrace = trace; // do something corrective if the trace starts in a solid... if ( trace.allsolid ) { if ( !PM_CorrectAllSolid(&trace) ) return; } // if the trace didn't hit anything, we are in free fall if ( trace.fraction == 1.0 ) { PM_GroundTraceMissed(); pml.groundPlane = qfalse; pml.walking = qfalse; return; } // check if getting thrown off the ground if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) { if ( pm->debugLevel ) { Com_Printf("%i:kickoff\n", c_pmove); } // go into jump animation if ( pm->cmd.forwardmove >= 0 ) { PM_ForceLegsAnim( LEGS_JUMP ); pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; } else { PM_ForceLegsAnim( LEGS_JUMPB ); pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; } pm->ps->groundEntityNum = ENTITYNUM_NONE; pml.groundPlane = qfalse; pml.walking = qfalse; return; } // slopes that are too steep will not be considered onground if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) { if ( pm->debugLevel ) { Com_Printf("%i:steep\n", c_pmove); } // FIXME: if they can't slide down the slope, let them // walk (sharp crevices) pm->ps->groundEntityNum = ENTITYNUM_NONE; pml.groundPlane = qtrue; pml.walking = qfalse; return; } pml.groundPlane = qtrue; pml.walking = qtrue; // hitting solid ground will end a waterjump if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) { pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND); pm->ps->pm_time = 0; } if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) { // just hit the ground if ( pm->debugLevel ) { Com_Printf("%i:Land\n", c_pmove); } PM_CrashLand(); // don't do landing time if we were just going down a slope if ( pml.previous_velocity[2] < -200 ) { // don't allow another jump for a little while pm->ps->pm_flags |= PMF_TIME_LAND; pm->ps->pm_time = 250; } } pm->ps->groundEntityNum = trace.entityNum; // don't reset the z velocity for slopes // pm->ps->velocity[2] = 0; PM_AddTouchEnt( trace.entityNum ); }
qboolean PM_SlideMove( qboolean gravity ) { int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t normal, 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; //qboolean damageSelf = qtrue; numbumps = 4; VectorCopy (pm->ps->velocity, primal_velocity); VectorCopy (pm->ps->velocity, endVelocity); if ( gravity ) { 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 ) { if ( PM_GroundSlideOkay( pml.groundTrace.plane.normal[2] ) ) {// 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] ); if ( !PM_GroundSlideOkay( planes[0][2] ) ) { planes[0][2] = 0; VectorNormalize( 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); //Normal player tracemask is SOLID,PLAYERCLIP,BODY,TERRAIN 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. wallbug!? 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 ); if (pm->ps->clientNum >= MAX_CLIENTS) { bgEntity_t *pEnt = pm_entSelf; if (pEnt && pEnt->s.eType == ET_NPC && pEnt->s.NPC_class == CLASS_VEHICLE && pEnt->m_pVehicle) { //do vehicle impact stuff then if (!pEnt->playerState->stats[STAT_RACEMODE]) PM_VehicleImpact(pEnt, &trace); } } #ifdef _GAME else { if ( PM_ClientImpact( &trace ) ) { continue; } } #endif time_left -= time_left * trace.fraction; if (numplanes >= MAX_CLIP_PLANES) { // this shouldn't really happen VectorClear( pm->ps->velocity ); return qtrue; } VectorCopy( trace.plane.normal, normal ); if ( !PM_GroundSlideOkay( normal[2] ) ) {//wall-running //never push up off a sloped wall normal[2] = 0; VectorNormalize( normal ); } // // if this is the same plane we hit before, nudge velocity // out along it, which fixes some epsilon issues with // non-axial planes // if ( !(pm->ps->pm_flags&PMF_STUCK_TO_WALL) ) {//no sliding if stuck to wall! for ( i = 0 ; i < numplanes ; i++ ) { if ( VectorCompare( normal, planes[i] ) ) {//DotProduct( normal, planes[i] ) > 0.99 ) { VectorAdd( normal, pm->ps->velocity, pm->ps->velocity ); break; } } if ( i < numplanes ) { continue; } } VectorCopy (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 triple 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 ); }
qboolean PM_SlideMove( float gravMod ) { int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t normal, 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; qboolean damageSelf = qtrue; int slideMoveContents = pm->tracemask; if ( pm->ps->clientNum >= MAX_CLIENTS && !PM_ControlledByPlayer() ) {//a non-player client, not an NPC under player control if ( pml.walking //walking on the ground || (pm->ps->groundEntityNum != ENTITYNUM_NONE //in air && PM_InSpecialJump( pm->ps->legsAnim )//in a special jump && !(pm->ps->eFlags&EF_FORCE_GRIPPED)//not being gripped && !(pm->ps->pm_flags&PMF_TIME_KNOCKBACK) && pm->gent && pm->gent->forcePushTime < level.time) )//not being pushed {// // If we're a vehicle, ignore this if we're being driven if ( !pm->gent //not an game ent || !pm->gent->client //not a client || pm->gent->client->NPC_class != CLASS_VEHICLE//not a vehicle || !pm->gent->m_pVehicle //no vehicle || !pm->gent->m_pVehicle->m_pPilot//no pilot || pm->gent->m_pVehicle->m_pPilot->s.number >= MAX_CLIENTS )//pilot is not the player {//then treat do not enter brushes as SOLID slideMoveContents |= CONTENTS_BOTCLIP; } } } numbumps = 4; VectorCopy (pm->ps->velocity, primal_velocity); if ( gravMod ) { VectorCopy( pm->ps->velocity, endVelocity ); if ( !(pm->ps->eFlags&EF_FORCE_GRIPPED) && !(pm->ps->eFlags&EF_FORCE_DRAINED) ) { endVelocity[2] -= pm->ps->gravity * pml.frametime * gravMod; } pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5; primal_velocity[2] = endVelocity[2]; if ( pml.groundPlane ) { if ( PM_GroundSlideOkay( pml.groundTrace.plane.normal[2] ) ) {// 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] ); if ( !PM_GroundSlideOkay( planes[0][2] ) ) { planes[0][2] = 0; VectorNormalize( 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, slideMoveContents ); if ( (trace.contents&CONTENTS_BOTCLIP) && (slideMoveContents&CONTENTS_BOTCLIP) ) {//hit a do not enter brush if ( trace.allsolid || trace.startsolid )//inside the botclip {//crap, we're in a do not enter brush, take it out for the remainder of the traces and re-trace this one right now without it slideMoveContents &= ~CONTENTS_BOTCLIP; pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, slideMoveContents ); } else if ( trace.plane.normal[2] > 0.0f ) {//on top of a do not enter brush, it, just redo this one trace without it pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, (slideMoveContents&~CONTENTS_BOTCLIP) ); } } 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 ); //Hit it if ( trace.surfaceFlags&SURF_NODAMAGE ) { damageSelf = qfalse; } else if ( trace.entityNum == ENTITYNUM_WORLD && trace.plane.normal[2] > 0.5f ) {//if we land on the ground, let falling damage do it's thing itself, otherwise do impact damage damageSelf = qfalse; } else { damageSelf = qtrue; } if ( PM_ClientImpact( &trace, damageSelf ) ) { continue; } if (pm->gent->client && pm->gent->client->NPC_class == CLASS_VEHICLE && trace.plane.normal[2]<pm->gent->m_pVehicle->m_pVehicleInfo->maxSlope ) { pm->ps->pm_flags |= PMF_BUMPED; } time_left -= time_left * trace.fraction; if ( numplanes >= MAX_CLIP_PLANES ) {// this shouldn't really happen VectorClear( pm->ps->velocity ); return qtrue; } VectorCopy( trace.plane.normal, normal ); if ( !PM_GroundSlideOkay( normal[2] ) ) {//wall-running //never push up off a sloped wall normal[2] = 0; VectorNormalize( normal ); } // // if this is the same plane we hit before, nudge velocity // out along it, which fixes some epsilon issues with // non-axial planes // if ( !(pm->ps->pm_flags&PMF_STUCK_TO_WALL) ) {//no sliding if stuck to wall! for ( i = 0 ; i < numplanes ; i++ ) { if ( DotProduct( normal, planes[i] ) > 0.99 ) { VectorAdd( normal, pm->ps->velocity, pm->ps->velocity ); break; } } if ( i < numplanes ) { continue; } } VectorCopy( 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 triple 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 ( gravMod ) { 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 ); }
qbool PM_SlideMove(Pmove *pm, Pml *pml, qbool gravity) { int i, j, k, bumpcount, numbumps, numplanes; Vec3 dir; float d, time_left, into; Vec3 planes[MAX_CLIP_PLANES]; Vec3 primal_velocity, clipVelocity; Trace trace; Vec3 end, endVelocity, endClipVelocity; numbumps = 4; copyv3(pm->ps->velocity, primal_velocity); if(gravity){ copyv3(pm->ps->velocity, endVelocity); endVelocity[2] -= pm->ps->gravity * pml->frametime; pm->ps->velocity[2] = (pm->ps->velocity[2] + endVelocity[2]) * 0.5f; 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; copyv3(pml->groundTrace.plane.normal, planes[0]); }else numplanes = 0; /* never turn against original velocity */ norm2v3(pm->ps->velocity, planes[numplanes]); numplanes++; for(bumpcount=0; bumpcount < numbumps; bumpcount++){ /* calculate position we are trying to move to */ saddv3(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 */ copyv3 (trace.endpos, pm->ps->origin); if(trace.fraction == 1) break; /* moved the entire distance */ /* save entity for contact */ PM_AddTouchEnt(pm, trace.entityNum); time_left -= time_left * trace.fraction; if(numplanes >= MAX_CLIP_PLANES){ /* this shouldn't really happen */ clearv3(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(dotv3(trace.plane.normal, planes[i]) > 0.99f){ addv3(trace.plane.normal, pm->ps->velocity, pm->ps->velocity); break; } if(i < numplanes) continue; copyv3 (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 = dotv3(pm->ps->velocity, planes[i]); if(into >= 0.1f) 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(dotv3(clipVelocity, planes[j]) >= 0.1f) 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(dotv3(clipVelocity, planes[i]) >= 0) continue; /* slide the original velocity along the crease */ crossv3 (planes[i], planes[j], dir); normv3(dir); d = dotv3(dir, pm->ps->velocity); scalev3(dir, d, clipVelocity); crossv3 (planes[i], planes[j], dir); normv3(dir); d = dotv3(dir, endVelocity); scalev3(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(dotv3(clipVelocity, planes[k]) >= 0.1f) continue; /* move doesn't interact with the plane */ /* stop dead at a triple plane interaction */ clearv3(pm->ps->velocity); return qtrue; } } /* if we have fixed all interactions, try another move */ copyv3(clipVelocity, pm->ps->velocity); copyv3(endClipVelocity, endVelocity); break; } } if(gravity) copyv3(endVelocity, pm->ps->velocity); /* don't change velocity if in a timer (FIXME: is this correct?) */ if(pm->ps->pm_time) copyv3(primal_velocity, pm->ps->velocity); return (bumpcount != 0); }
bool PM_SlideMove( bool gravity ) #endif { int bumpcount, numbumps; #ifdef UNREALARENA int fallingcount = 0; #endif 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 ); #ifndef UNREALARENA VectorCopy( pm->ps->velocity, endVelocity ); #endif if ( gravity ) { #ifdef UNREALARENA VectorCopy( pm->ps->velocity, endVelocity ); #endif 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 ); } } 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 // spectators ignore movers, so that they can noclip through doors pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask, ( pm->ps->pm_type == PM_SPECTATOR ) ? CONTENTS_MOVER : 0 ); 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 true; } if ( trace.fraction > 0 ) { #ifdef UNREALARENA vec3_t pos; VectorCopy( trace.endpos, pos ); pos[ 2 ] -= stepsize; if ( PM_CheckFallingFromLedge( pos ) ) { vec3_t normal; // using pos in place of trace.endpos as it should give better results PM_FindLedgeNormal( pm->ps->origin, pos, normal ); // if we can't determine the ledge plane then stop everything if ( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && normal[ 2 ] == 0.0f ) { VectorClear( pm->ps->velocity ); fallingcount++; break; } // slide along the ledge plane PM_ClipVelocity( pm->ps->velocity, normal, pm->ps->velocity ); fallingcount++; continue; } #endif // 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 true; } // // 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 ); #ifdef UNREALARENA if ( gravity ) { // slide along the plane PM_ClipVelocity( endVelocity, planes[ i ], endClipVelocity ); } #else // slide along the plane PM_ClipVelocity( endVelocity, planes[ i ], endClipVelocity ); #endif // 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 ); #ifdef UNREALARENA if ( gravity ) { PM_ClipVelocity( endClipVelocity, planes[ j ], endClipVelocity ); } #else PM_ClipVelocity( endClipVelocity, planes[ j ], endClipVelocity ); #endif // 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 ); #ifdef UNREALARENA if ( gravity ) { CrossProduct( planes[ i ], planes[ j ], dir ); VectorNormalize( dir ); d = DotProduct( dir, endVelocity ); VectorScale( dir, d, endClipVelocity ); } #else CrossProduct( planes[ i ], planes[ j ], dir ); VectorNormalize( dir ); d = DotProduct( dir, endVelocity ); VectorScale( dir, d, endClipVelocity ); #endif // see if there is a third plane 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 true; } } // if we have fixed all interactions, try another move VectorCopy( clipVelocity, pm->ps->velocity ); #ifdef UNREALARENA if ( gravity ) { VectorCopy( endClipVelocity, endVelocity ); } #else VectorCopy( endClipVelocity, endVelocity ); #endif 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 ); } #ifdef UNREALARENA bumpcount -= fallingcount; #endif return ( bumpcount != 0 ); }